/*--------------------------------------------------------------------------*/
/* ALBERTA:  an Adaptive multi Level finite element toolbox using           */
/*           Bisectioning refinement and Error control by Residual          */
/*           Techniques for scientific Applications                         */
/*                                                                          */
/* file:     refine_1d.c                                                    */
/*                                                                          */
/* description:  recursive refinement of 1 dim. hierarchical meshes;        */
/*               implementation of the newest vertex bisection              */
/*               file contains all routines depending on DIM == 1;          */
/*                                                                          */
/*--------------------------------------------------------------------------*/
/*                                                                          */
/*  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                                    */
/*                                                                          */
/*  http://www.mathematik.uni-freiburg.de/IAM/ALBERTA                       */
/*                                                                          */
/*  (c) by A. Schmidt and K.G. Siebert (1996-2003)                          */
/*                                                                          */
/*--------------------------------------------------------------------------*/

/*--------------------------------------------------------------------------*/
/* Compute new coordinates for affine parametric meshes                     */
/*--------------------------------------------------------------------------*/

static void new_coords_1d(const EL_INFO *el_info)
{
  EL      *el = el_info->el;
  static const REAL_B mid_lambda = { 0.5, 0.5 };

  if (el_info->active_projection
      && el_info->active_projection->func && (el->new_coord == NULL)) {
    el->new_coord = get_real_d(el_info->mesh);

    AXPBY_DOW(0.5, el_info->coord[0], 0.5, el_info->coord[1], el->new_coord);
    el_info->active_projection->func(el->new_coord, el_info, mid_lambda);

    _AI_refine_update_bbox(el_info->mesh, el->new_coord);    
  }
}

/*--------------------------------------------------------------------------*/
/*  AI_refine_fct_1d: bisects a single element into child[0] and child[1]   */
/*  WARNING: This function is called directly from submesh.c!               */
/*--------------------------------------------------------------------------*/

void AI_refine_fct_1d(const EL_INFO *el_info, void *data)
{
  MESH       *mesh = el_info->mesh;
  EL         *el = el_info->el, *child[2];

  if (el->mark <= 0) {
    return;
  }

/*--------------------------------------------------------------------------*/
/* generate new co-ordinates if necessary. We do this before calling        */
/* refine_leaf_data() such that the application can use the parents leaf-   */
/* data structure while generating the new coordinates for the childs.      */
/*--------------------------------------------------------------------------*/
  if (!mesh->parametric) {
    new_coords_1d(el_info);
  }

  child[0] = get_element(mesh);
  child[1] = get_element(mesh);
  child[0]->mark = child[1]->mark = MAX(0, el->mark-1);
  el->mark = 0;

/*--------------------------------------------------------------------------*/
/*  transfer hidden data from parent to children                            */
/*--------------------------------------------------------------------------*/

  if (el->child[1] && 
      ((MESH_MEM_INFO *)mesh->mem_info)->leaf_data_info->refine_leaf_data)
    ((MESH_MEM_INFO *)mesh->mem_info)->leaf_data_info->refine_leaf_data(el,
									child);

  AI_free_leaf_data((void *) el->child[1], mesh);

  el->child[0] = child[0];
  el->child[1] = child[1];
  
  if (child[0]->mark > 0) do_more_refine_1d = true;

  if(mesh->n_dof[VERTEX]) {
    child[0]->dof[1] = child[1]->dof[0] = get_dof(mesh, VERTEX);

/*--------------------------------------------------------------------------*/
/*  the other vertices are handed on from the parent                        */
/*--------------------------------------------------------------------------*/
    child[0]->dof[0] = el->dof[0];
    child[1]->dof[1] = el->dof[1];
  }

/*--------------------------------------------------------------------------*/
/*  there is one more leaf element, two hierachical elements,               */
/*  one more vertex                                                         */
/*--------------------------------------------------------------------------*/

  mesh->n_elements++;
  mesh->n_hier_elements += 2;

  if (mesh->n_vertices > -1) {
    mesh->n_vertices++;
    mesh->per_n_vertices++;
  }

  if (mesh->n_dof[CENTER]) {
/*--------------------------------------------------------------------------*/
/* there are dofs at the barycenter of the triangles                        */
/*--------------------------------------------------------------------------*/
    child[0]->dof[mesh->node[CENTER]] = get_dof(mesh, CENTER);
    child[1]->dof[mesh->node[CENTER]] = get_dof(mesh, CENTER);
  }

/*--------------------------------------------------------------------------*/
/*  if there are functions to interpolate data to the finer grid, do so     */
/*--------------------------------------------------------------------------*/
  
  if (call_refine_interpol_1d) {
    RC_LIST_EL ref_list[1] = {{{0}}};

    ref_list->el_info = *el_info;
    refine_interpol(mesh, ((MESH_MEM_INFO *)mesh->mem_info)->dvlist,
		    ref_list, 1);
  }

  if (mesh->n_dof[CENTER]) {
    free_dof(el->dof[mesh->node[CENTER]], mesh, CENTER, true);
  }
}


static U_CHAR refine_1d(MESH *mesh, FLAGS fill_flags)
{
  int   n_elements = mesh->n_elements;
  int   is_periodic;

  fill_flags |= CALL_LEAF_EL;

  if(mesh->parametric) {
    fill_flags |= FILL_PROJECTION;
  } else {
    int i;
    
    for (i = 0; i < mesh->n_macro_el; i++) {
      MACRO_EL *mel = mesh->macro_els+i;
      if (mel->projection[0] != NULL ||
	  mel->projection[1] != NULL ||
	  mel->projection[2] != NULL) {
	fill_flags |= FILL_PROJECTION|FILL_COORDS;
	break;
      }
    }
  }
  if (get_master(mesh) != NULL) {
    fill_flags |= FILL_MASTER_INFO;
  }

  is_periodic = mesh->is_periodic;
  mesh->is_periodic = false;
  call_refine_interpol_1d =
    count_refine_interpol(mesh, AI_get_dof_vec_list(mesh), false, &fill_flags);
  mesh->is_periodic = is_periodic;  
  
  do_more_refine_1d = true;
  while (do_more_refine_1d) {
    do_more_refine_1d = false;
    mesh_traverse(mesh, -1, fill_flags, AI_refine_fct_1d, NULL);
  }
  n_elements = mesh->n_elements - n_elements;

  return n_elements ? MESH_REFINED : 0;
}
