/*--------------------------------------------------------------------------*/
/* ALBERTA:  an Adaptive multi Level finite element toolbox using           */
/*           Bisectioning refinement and Error control by Residual          */
/*           Techniques for scientific Applications                         */
/*                                                                          */
/* file:     coarsen_1d.c                                                   */
/*                                                                          */
/* description:  coarsening of 1 dim. hierarchical meshes;                  */
/*               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)                          */
/*                                                                          */
/*--------------------------------------------------------------------------*/

/*--------------------------------------------------------------------------*/
/*  AI_coarsen_fct_1d: coarsens a single element of the coarsening          */
/*  patch dofs in the interior of the element are removed; dofs for higher  */
/*  order at the boundary or the coarsening patch still belong to           */
/*  the parent. Do not remove them from the mesh!!!                         */
/*  WARNING: This function is called directly from submesh.c!               */
/*--------------------------------------------------------------------------*/

void AI_coarse_fct_1d(const EL_INFO *el_info, void *dummy)
{
  FUNCNAME("AI_coarsen_fct_1d");
  MESH *mesh = el_info->mesh;
  EL   *el = el_info->el;
  int  mark;

  INFO(0,2,"\n");
  if (!(el->child[0])) return;   /* single leaves don't get coarsened       */

  mark = MAX(el->child[0]->mark, el->child[1]->mark);
  el->mark = MIN(mark+1, 0);

  if (mark >= 0) {
/*--------------------------------------------------------------------------*/
/*  one of the children must not be coarsened; return :-(                   */
/*--------------------------------------------------------------------------*/
    if (el->child[0]->mark < 0) {
      el->child[0]->mark = 0;
    }
    if (el->child[1]->mark < 0) {
      el->child[1]->mark = 0;
    }
    return;
  } else {
    EL       *child[2];

    child[0] = el->child[0];
    child[1] = el->child[1]; 

/*--------------------------------------------------------------------------*/
/*--- and now coarsen child[0] and child[1] into parent                  ---*/
/*--------------------------------------------------------------------------*/
  
/*--------------------------------------------------------------------------*/
/*--- hand DOFs from children to parent, and add DOF at center           ---*/
/*--------------------------------------------------------------------------*/
    if (mesh->n_dof[CENTER])
      AI_reactivate_dof(mesh, el, NULL, NULL);

/*--------------------------------------------------------------------------*/
/*  restrict dof vectors to the parents on the patch                        */
/*--------------------------------------------------------------------------*/

    if (call_coarse_restrict_1d) {
      RC_LIST_EL  coarse_list;
      
      coarse_list.el_info = *el_info;
      coarse_restrict(mesh, ((MESH_MEM_INFO *)mesh->mem_info)->dvlist,
		      &coarse_list, 1);
    }

/*--------------------------------------------------------------------------*/
/*--- remove all DOFs of children that are not used anymore              ---*/
/*--------------------------------------------------------------------------*/

    if (mesh->n_dof[VERTEX])       /*---  midpoint of parent          ---*/
    {
      free_dof(child[1]->dof[mesh->node[VERTEX]], mesh, VERTEX, false);
    }

    if (mesh->n_dof[CENTER])       /*--- center of the children       ---*/
    {
      free_dof(child[0]->dof[mesh->node[CENTER]], mesh, CENTER, false);
      free_dof(child[1]->dof[mesh->node[CENTER]], mesh, CENTER, false);
    }

    el->child[0] = NULL;
    el->child[1] = (EL *)AI_get_leaf_data(mesh);

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

    free_element(child[0], mesh);
    free_element(child[1], mesh);

    if (el->new_coord) {
      free_real_d(mesh, el->new_coord);
      el->new_coord = NULL;
    }

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

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

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

  fill_flags |= CALL_EVERY_EL_POSTORDER;

  is_periodic = mesh->is_periodic;
  mesh->is_periodic = false;
  call_coarse_restrict_1d =
    count_coarse_restrict(mesh, AI_get_dof_vec_list(mesh), false);
  mesh->is_periodic = is_periodic;

  mesh_traverse(mesh, -1, fill_flags, AI_coarse_fct_1d, NULL);

  return (mesh->n_elements < n_elements) ? MESH_COARSENED : 0;
}
