Program Listing for File adapt.hxx

Return to documentation for file (mesh_handle/internal/adapt.hxx)

/*
  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 classes in parallel.

  Copyright (C) 2026 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.
*/

#pragma once

#include <t8.h>
#include <t8_forest/t8_forest_general.h>
#include <mesh_handle/mesh.hxx>
#include <memory>
#include <span>

namespace t8_mesh_handle
{

namespace detail
{

struct mesh_adapt_context_base
{
  virtual ~mesh_adapt_context_base () = default;

  virtual int
  adapt_mesh (const t8_locidx_t lelement_handle_id, const int num_elements)
    = 0;
};

template <typename TMeshClass>
struct mesh_adapt_context final: mesh_adapt_context_base
{
  mesh_adapt_context (TMeshClass& mesh_handle, typename TMeshClass::adapt_callback_type adapt_callback)
    : m_mesh_handle (mesh_handle), m_adapt_callback (std::move (adapt_callback))
  {
  }

  int
  adapt_mesh (const t8_locidx_t lelement_handle_id, const int num_elements) override
  {
    // Check if adapt callback is set and call it using the correct mesh handle function arguments.
    T8_ASSERTF (m_adapt_callback, "No adapt callback set.");
    std::span<const typename TMeshClass::element_class> element_view (&m_mesh_handle[lelement_handle_id], num_elements);
    return m_adapt_callback (m_mesh_handle, element_view);
  }

 private:
  TMeshClass& m_mesh_handle;
  typename TMeshClass::adapt_callback_type m_adapt_callback;
};

class adapt_registry {
 public:
  static void
  register_context (t8_forest_t forest, std::unique_ptr<mesh_adapt_context_base> context)
  {
    auto& map = get_map ();
    auto [it, inserted] = map.emplace (forest, std::move (context));
    if (!inserted) {
      t8_global_errorf ("ERROR: Context already registered!");
    }
  }

  static void
  unregister_context (t8_forest_t forest)
  {
    auto& map = get_map ();
    [[maybe_unused]] const auto erased = map.erase (forest);
    T8_ASSERT (erased == 1);
  }

  static mesh_adapt_context_base*
  get (t8_forest_t forest)
  {
    const auto& map = get_map ();
    const auto it = map.find (forest);
    return it != map.end () ? it->second.get () : nullptr;
  }

 private:
  static std::unordered_map<t8_forest_t, std::unique_ptr<mesh_adapt_context_base>>&
  get_map ()
  {
    static std::unordered_map<t8_forest_t, std::unique_ptr<mesh_adapt_context_base>> map;
    return map;
  }
};

int
mesh_adapt_callback_wrapper ([[maybe_unused]] t8_forest_t forest, t8_forest_t forest_from, t8_locidx_t which_tree,
                             t8_eclass_t tree_class, t8_locidx_t lelement_id, [[maybe_unused]] const t8_scheme* scheme,
                             const int is_family, const int num_elements, t8_element_t* elements[])
{
  if (is_family && !scheme->elements_are_family (tree_class, elements)) {
    t8_global_errorf ("ERROR: The mesh handle does not support deleted elements.");
    return 0;  // No adaptation as default.
  }
  // Get static adapt context from the registry.
  // Via this, we can access the mesh handle and the user defined adapt callback that uses mesh handle functionality.
  auto* context = adapt_registry::get (forest_from);
  if (!context) {
    t8_global_errorf (
      "ERROR: Something went wrong while registering the adaptation callbacks. Please check your implementation.");
    return 0;  // No adaptation as default.
  }
  // Convert to index used in the mesh handle.
  const t8_locidx_t mesh_index = t8_forest_get_tree_element_offset (forest_from, which_tree) + lelement_id;
  // Call the actual adapt callback stored in the context.
  return context->adapt_mesh (mesh_index, num_elements);
}

}  // namespace detail
}  // namespace t8_mesh_handle