Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
DLR-AMR
GitHub Repository: DLR-AMR/t8code
Path: blob/main/example/common/t8_example_common.cxx
901 views
/*
  This file is part of t8code.
  t8code is a C library to manage a collection (a forest) of multiple
  connected adaptive space-trees of general element types in parallel.

  Copyright (C) 2015 the developers

  t8code 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
  (at your option) any later version.

  t8code 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.

  You should have received a copy of the GNU General Public License
  along with t8code; if not, write to the Free Software Foundation, Inc.,
  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

/** \file t8_example_common.cxx Provide routines that are used in more than one
  * example. */

#include <sc_refcount.h>
#include <t8_forest/t8_forest_adapt.h>
#include <t8_schemes/t8_scheme.hxx>
#include <t8_forest/t8_forest_general.h>
#include <t8_forest/t8_forest_geometrical.h>
#include <example/common/t8_example_common.hxx>

/* Adapt a forest such that always the second child of the first
 * tree is refined and no other elements. This results in a highly
 * imbalanced forest.
 * The user data of forest must an integer set to the maximum refinement level.
 */
int
t8_common_adapt_balance (t8_forest_t forest, t8_forest_t forest_from, t8_locidx_t which_tree,
                         const t8_eclass_t tree_class, [[maybe_unused]] t8_locidx_t lelement_id,
                         const t8_scheme *scheme, [[maybe_unused]] const int is_family,
                         [[maybe_unused]] const int num_elements, t8_element_t *elements[])
{
  int level;
  int maxlevel, child_id;
  T8_ASSERT (!is_family || num_elements == scheme->element_get_num_children (tree_class, elements[0]));
  level = scheme->element_get_level (tree_class, elements[0]);

  /* we set a maximum refinement level as forest user data */
  maxlevel = *(int *) t8_forest_get_user_data (forest);
  if (level >= maxlevel) {
    /* Do not refine after the maxlevel */
    return 0;
  }
  child_id = scheme->element_get_child_id (tree_class, elements[0]);
  /* refine the last child of even trees */
  if ((which_tree + t8_forest_get_first_local_tree_id (forest_from)) % 2 == 0
      && child_id == scheme->element_get_num_children (tree_class, elements[0]) - 1) {
    return 1;
  }
  return 0;
}

int
t8_common_within_levelset (t8_forest_t forest, const t8_locidx_t ltreeid, const t8_element_t *element,
                           t8_example_level_set_fn levelset, double band_width, double t, void *udata)
{
  t8_3D_point elem_midpoint;
  double elem_diam;
  double value;
  const t8_eclass_t tree_class = t8_forest_get_eclass (forest, ltreeid);
  const t8_scheme *scheme = t8_forest_get_scheme (forest);

  T8_ASSERT (band_width >= 0);
  if (band_width == 0) {
    /* If bandwidth = 0, we only refine the elements that are intersected by the zero level-set */
    const int num_corners = scheme->element_get_num_corners (tree_class, element);
    int sign = 1, icorner;
    t8_3D_point coords;

    /* Compute LS function at first corner */
    t8_forest_element_coordinate (forest, ltreeid, element, 0, coords.data ());
    /* compute the level-set function at this corner */
    value = levelset (coords, t, udata);
    /* sign = 1 if value > 0, -1 if value < 0, 0 if value = 0 */
    sign = value > 0 ? 1 : -(value < 0);
    /* iterate over all corners */
    for (icorner = 1; icorner < num_corners; icorner++) {
      t8_forest_element_coordinate (forest, ltreeid, element, icorner, coords.data ());
      /* compute the level-set function at this corner */
      value = levelset (coords, t, udata);
      if ((value > 0 && sign <= 0) || (value == 0 && sign != 0) || (value < 0 && sign >= 0)) {
        /* The sign of the LS function changes across the element, we refine it */
        return 1;
      }
    }
    return 0;
  }

  /* Compute the coordinates of the anchor node X. */
  t8_forest_element_centroid (forest, ltreeid, element, elem_midpoint.data ());
  /* Compute the element's diameter */
  elem_diam = t8_forest_element_diam (forest, ltreeid, element);
  /* Compute L(X) */
  value = levelset (elem_midpoint, t, udata);

  if (fabs (value) < band_width * elem_diam) {
    /* The element is in the band that should be refined. */
    return 1;
  }
  return 0;
}

/** Adapt a forest along a given level-set function.
 * The user data of forest must be a pointer to a \a t8_example_level_set_struct_t.
 * An element in the forest is refined, if it is in a band of \a band_with many
 * \a max_level elements around the zero level-set Gamma = { x | L(x) = 0}
 */
/* TODO: Currently the band_width control is not working yet. */
int
t8_common_adapt_level_set (t8_forest_t forest, t8_forest_t forest_from, t8_locidx_t which_tree,
                           const t8_eclass_t tree_class, [[maybe_unused]] t8_locidx_t lelement_id,
                           const t8_scheme *scheme, const int is_family, [[maybe_unused]] const int num_elements,
                           t8_element_t *elements[])
{
  t8_example_level_set_struct_t *data;
  int within_band;
  int level;

  T8_ASSERT (!is_family || num_elements == scheme->element_get_num_children (tree_class, elements[0]));

  data = (t8_example_level_set_struct_t *) t8_forest_get_user_data (forest);
  level = scheme->element_get_level (tree_class, elements[0]);

  /* Get the minimum and maximum x-coordinate from the user data pointer of forest */
  data = (t8_example_level_set_struct_t *) t8_forest_get_user_data (forest);

  /* If maxlevel is exceeded then coarsen */
  if (level > data->max_level && is_family) {
    return -1;
  }
  /* Refine at least until min level */
  if (level < data->min_level) {
    return 1;
  }
  within_band = t8_common_within_levelset (forest_from, which_tree, elements[0], data->L, data->band_width / 2, data->t,
                                           data->udata);
  if (within_band && level < data->max_level) {
    /* The element can be refined and lies inside the refinement region */
    return 1;
  }
  else if (is_family && level > data->min_level && !within_band) {
    /* If element lies out of the refinement region and a family was given
     * as argument, we coarsen to level base level */
    return -1;
  }
  return 0;
}