/*--------------------------------------------------------------------------*/
/* ALBERTA:  an Adaptive multi Level finite element toolbox using           */
/*           Bisectioning refinement and Error control by Residual          */
/*           Techniques for scientific Applications                         */
/*                                                                          */
/* file:     alberta-grape.c                                                */
/*                                                                          */
/*--------------------------------------------------------------------------*/
/*                                                                          */
/*  authors:   Alfred Schmidt                                               */
/*             Zentrum fuer Technomathematik                                */
/*             Fachbereich 3 Mathematik/Informatik                          */
/*             Universitaet Bremen                                          */
/*             Bibliothekstr. 2                                             */
/*             D-28359 Bremen, Germany                                      */
/*                                                                          */
/*             Kunibert G. Siebert                                          */
/*             Institut fuer Mathematik                                     */
/*             Universitaet Augsburg                                        */
/*             Universitaetsstr. 14                                         */
/*             D-86159 Augsburg, Germany                                    */
/*                                                                          */
/*             Claus-Justus Heine                                           */
/*             Abteilung fuer Angewandte Mathematik                         */
/*             Albert-Ludwigs-Universitaet Freiburg                         */
/*             Hermann-Herder-Str. 10                                       */
/*             D-79104 Freiburg im Breisgau, Germany                        */
/*                                                                          */
/*             Robert Kloefkorn                                             */
/*             Abteilung fuer Angewandte Mathematik                         */
/*             Albert-Ludwigs-Universitaet Freiburg                         */
/*             Hermann-Herder-Str. 10                                       */
/*             D-79104 Freiburg im Breisgau, Germany                        */
/*                                                                          */
/*  http://www.alberta-fem.de/                                              */
/*                                                                          */
/*--------------------------------------------------------------------------*/
/*  (c) by A. Schmidt and K.G. Siebert (1996-2004)                          */
/*         C.-J. Heine and R. Kloefkorn (1998-2007)                         */
/*                                                                          */
/*     This program is free software; you can redistribute it and/or modify */
/*     it under the terms of the GNU General Public License as published by */
/*     the Free Software Foundation; either version 2 of the License, or    */
/*     any later version.                                                   */
/*                                                                          */
/*     This program is distributed in the hope that it will be useful,      */
/*     but WITHOUT ANY WARRANTY; without even the implied warranty of       */
/*     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        */
/*     GNU General Public License for more details.                         */
/*--------------------------------------------------------------------------*/

#include <grape.h>
#undef REFINE
#undef COARSE

#include <alberta/alberta.h>

#ifndef G_CONST
#define G_CONST
#endif


#if ADD_Z
static float z(float x, float y)
{
#if 0
  return(0.0);
#endif
#if 1
  return(sin(x)+sin(y));
#endif
}
#endif


/****************************************************************************/
/*  Grape definitions for triangles 					    */
/****************************************************************************/

static G_CONST double t_c_0[3] = {1., 0., 0.}, t_c_1[3] = {0., 1., 0.};
static G_CONST double t_c_2[3] = {0., 0., 1.};

static G_CONST double *tria_coord[3] = {t_c_0,t_c_1,t_c_2};

/****************************************************************************/
/*  transformations between local and global coordinates		    */
/****************************************************************************/

static int tria_check_inside(ELEMENT2D *el, double G_CONST *coord)
{
  if      (coord[0] < 0.0) return(0);
  else if (coord[1] < 0.0) return(1);
  else if (coord[2] < 0.0) return(2);
  else
    return(INSIDE);
}

/****************************************************************************/

static int tria_world_to_coord(ELEMENT2D *el, double G_CONST *xyz, double *coord)
{
  FUNCNAME("tria_world_to_coord");
  EL_INFO    *el_info;
  MATRIX22   a;
  VEC2       b;
  int        i,j;

  ASSURE(el, "no element", return(-2));
  ASSURE(el_info = (EL_INFO *)el->user_data, "no EL_INFO", return(-2));

  TEST_FLAG(FILL_COORDS, el_info);

  /* compute the barycentric coordinates of point xyx */
  /* by solving the linear system:
         ( x0-x2  x1-x2 )  ( coord[0] )  =   ( x - x2)
         ( y0-y2  y1-y2 )  ( coord[1] )  =   ( y - y2)

         coord[2] : = 1 - coord[0] - coord[1]
  */

  for (i=0; i<2; i++) 
    for (j=0; j<2; j++) 
      a[j][i] =  el->vertex[i][j] - el->vertex[2][j];

  for (j=0; j<2; j++) 
    b[j] = xyz[j] - el->vertex[2][j];

  if(!g_solve2((void *) a, b, coord)){
    printf("ERROR in g_solve2()\n");
    return(-2);
  }
  coord[2] = 1.0 - coord[0] - coord[1];

  return(tria_check_inside(el,coord));
}

/****************************************************************************/

static void tria_coord_to_world(ELEMENT2D *el, double G_CONST *coord, double *world)
{
  FUNCNAME("tria_coord_to_world");
  EL_INFO *elinfo = (EL_INFO *)(el->user_data);

  TEST_FLAG(FILL_COORDS, elinfo);

  world[0] =  coord[0] * elinfo->coord[0][0] 
            + coord[1] * elinfo->coord[1][0]
            + coord[2] * elinfo->coord[2][0] ;
  world[1] =  coord[0] * elinfo->coord[0][1] 
            + coord[1] * elinfo->coord[1][1]
            + coord[2] * elinfo->coord[2][1] ;
#if DIM_OF_WORLD > 2
  world[2] =  coord[0] * elinfo->coord[0][2] 
            + coord[1] * elinfo->coord[1][2]
            + coord[2] * elinfo->coord[2][2] ;
#else
#if ADD_Z
  world[2] = z(world[0],world[1]);
#endif
#endif
  return;
}

/****************************************************************************/

static ELEMENT2D  *tria_neighbour(ELEMENT2D *el, int pn, int ii, 
				  double *coord, double *xyz,
				  MESH_ELEMENT_FLAGS flags)
{
  FUNCNAME("tria_neighbour");
  MSG("not yet implemented\n");

  /* traverse_neighbour(...); */

  return(NULL);
}

/****************************************************************************/

static int  tria_boundary(ELEMENT2D *el, int pn)
{
  FUNCNAME("tria_boundary");
  EL_INFO        *elinfo = (EL_INFO *)(el->user_data);

  ASSURE(el, "tria_boundary: no element", return(-2));
  ASSURE(elinfo, "tria_boundary: no EL_INFO", return(-2));
  TEST_FLAG(FILL_BOUND, elinfo);

  return wall_bound(elinfo, (pn+2) % N_WALLS_2D);
}

/****************************************************************************/
/****************************************************************************/

static ELEMENT2D_DESCRIPTION tria_description =
{
 0,   /*  dindex. cH: offset into a C-style array. Keep it at zero */
 3,           /* number_of_vertices     */
 3,           /* dimension_of_coord     */
 tria_coord, 
 1,           /* parametric_degree      */
 tria_world_to_coord, tria_coord_to_world, 
 tria_check_inside,  tria_neighbour, tria_boundary
};

/****************************************************************************/
/*  common routines for triangles and tetrahedra                            */
/*  including typedefs for: GRAPE_ELEMENT, GRAPE_MESH, F_EL_INFO, F_DATA    */
/****************************************************************************/

#include "../Common/mesh_interface_common_c.h"

/****************************************************************************/


