From 6ddf3e50679bf8a46314c10a7f852a79f65d8815 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Del=20Pino?= <stephane.delpino44@gmail.com>
Date: Fri, 13 Jun 2025 18:21:04 +0200
Subject: [PATCH] Add a polynomial basis data manager mechanism

It aims at storing on a given mesh some polynomial basis information
that can be expansive to compute. this may be useful for instance
during limitation process for polynomials of degree higher than 1.
---
 src/main.cpp                              |  3 ++
 src/mesh/CMakeLists.txt                   |  6 +++
 src/mesh/Mesh.cpp                         |  2 +
 src/scheme/CMakeLists.txt                 |  1 +
 src/scheme/PolynomialBasisData.hpp        | 46 ++++++++++++++++
 src/scheme/PolynomialBasisDataManager.cpp | 63 ++++++++++++++++++++++
 src/scheme/PolynomialBasisDataManager.hpp | 47 +++++++++++++++++
 src/scheme/PolynomialBasisDataVariant.hpp | 64 +++++++++++++++++++++++
 tests/mpi_test_main.cpp                   |  3 ++
 tests/test_main.cpp                       |  3 ++
 10 files changed, 238 insertions(+)
 create mode 100644 src/scheme/PolynomialBasisData.hpp
 create mode 100644 src/scheme/PolynomialBasisDataManager.cpp
 create mode 100644 src/scheme/PolynomialBasisDataManager.hpp
 create mode 100644 src/scheme/PolynomialBasisDataVariant.hpp

diff --git a/src/main.cpp b/src/main.cpp
index cbaf6277e..ed341a0a4 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -7,6 +7,7 @@
 #include <mesh/MeshDataManager.hpp>
 #include <mesh/StencilManager.hpp>
 #include <mesh/SynchronizerManager.hpp>
+#include <scheme/PolynomialBasisDataManager.hpp>
 #include <utils/ExecutionStatManager.hpp>
 #include <utils/GlobalVariableManager.hpp>
 #include <utils/PugsUtils.hpp>
@@ -32,6 +33,7 @@ main(int argc, char* argv[])
   RandomEngine::create();
   QuadratureManager::create();
   MeshDataManager::create();
+  PolynomialBasisDataManager::create();
   DualConnectivityManager::create();
   DualMeshManager::create();
   StencilManager::create();
@@ -44,6 +46,7 @@ main(int argc, char* argv[])
   StencilManager::destroy();
   DualMeshManager::destroy();
   DualConnectivityManager::destroy();
+  PolynomialBasisDataManager::destroy();
   MeshDataManager::destroy();
   QuadratureManager::destroy();
   RandomEngine::destroy();
diff --git a/src/mesh/CMakeLists.txt b/src/mesh/CMakeLists.txt
index 68c6de46d..be5b06977 100644
--- a/src/mesh/CMakeLists.txt
+++ b/src/mesh/CMakeLists.txt
@@ -54,3 +54,9 @@ target_link_libraries(
   ${PARMETIS_TARGET}
   ${HIGHFIVE_TARGET}
 )
+
+# Additional dependencies
+add_dependencies(
+  PugsMesh
+  PugsScheme
+)
diff --git a/src/mesh/Mesh.cpp b/src/mesh/Mesh.cpp
index baa0d00d7..6e368af53 100644
--- a/src/mesh/Mesh.cpp
+++ b/src/mesh/Mesh.cpp
@@ -3,11 +3,13 @@
 #include <mesh/Connectivity.hpp>
 #include <mesh/DualMeshManager.hpp>
 #include <mesh/MeshDataManager.hpp>
+#include <scheme/PolynomialBasisDataManager.hpp>
 
 template <size_t Dimension>
 Mesh<Dimension>::~Mesh()
 {
   MeshDataManager::instance().deleteMeshData(this->id());
+  PolynomialBasisDataManager::instance().deletePolynomialBasisData(this->id());
   DualMeshManager::instance().deleteMesh(this->id());
 }
 
diff --git a/src/scheme/CMakeLists.txt b/src/scheme/CMakeLists.txt
index 852a6cd75..7e5e0bf62 100644
--- a/src/scheme/CMakeLists.txt
+++ b/src/scheme/CMakeLists.txt
@@ -13,6 +13,7 @@ add_library(
   FluxingAdvectionSolver.cpp
   HyperelasticSolver.cpp
   LoadBalancer.cpp
+  PolynomialBasisDataManager.cpp
   PolynomialReconstruction.cpp
 )
 
diff --git a/src/scheme/PolynomialBasisData.hpp b/src/scheme/PolynomialBasisData.hpp
new file mode 100644
index 000000000..43640b00e
--- /dev/null
+++ b/src/scheme/PolynomialBasisData.hpp
@@ -0,0 +1,46 @@
+#ifndef POLYNOMIAL_BASIS_DATA_HPP
+#define POLYNOMIAL_BASIS_DATA_HPP
+
+#include <mesh/MeshTraits.hpp>
+
+template <size_t Dimension>
+class Mesh;
+
+template <MeshConcept MeshType>
+class PolynomialBasisData;
+
+template <size_t Dimension>
+class PolynomialBasisData<Mesh<Dimension>>
+{
+ public:
+  using MeshType = Mesh<Dimension>;
+
+  static_assert(Dimension > 0, "dimension must be strictly positive");
+  static_assert((Dimension <= 3), "only 1d, 2d and 3d are implemented");
+
+ private:
+  const MeshType& m_mesh;
+
+ public:
+  PUGS_INLINE
+  const MeshType&
+  mesh() const
+  {
+    return m_mesh;
+  }
+
+ private:
+  // PolynomialBasisData **must** be constructed through PolynomialBasisDataManager
+  friend class PolynomialBasisDataManager;
+  PolynomialBasisData(const MeshType& mesh) : m_mesh(mesh) {}
+
+ public:
+  PolynomialBasisData() = delete;
+
+  PolynomialBasisData(const PolynomialBasisData&) = delete;
+  PolynomialBasisData(PolynomialBasisData&&)      = delete;
+
+  ~PolynomialBasisData() {}
+};
+
+#endif   // POLYNOMIAL_BASIS_DATA_HPP
diff --git a/src/scheme/PolynomialBasisDataManager.cpp b/src/scheme/PolynomialBasisDataManager.cpp
new file mode 100644
index 000000000..8f659e923
--- /dev/null
+++ b/src/scheme/PolynomialBasisDataManager.cpp
@@ -0,0 +1,63 @@
+#include <utils/PugsAssert.hpp>
+
+#include <mesh/Connectivity.hpp>
+#include <mesh/Mesh.hpp>
+#include <scheme/PolynomialBasisData.hpp>
+#include <scheme/PolynomialBasisDataManager.hpp>
+#include <scheme/PolynomialBasisDataVariant.hpp>
+#include <utils/Exceptions.hpp>
+
+#include <sstream>
+
+PolynomialBasisDataManager* PolynomialBasisDataManager::m_instance{nullptr};
+
+void
+PolynomialBasisDataManager::create()
+{
+  Assert(m_instance == nullptr, "PolynomialBasisDataManager is already created");
+  m_instance = new PolynomialBasisDataManager;
+}
+
+void
+PolynomialBasisDataManager::destroy()
+{
+  Assert(m_instance != nullptr, "PolynomialBasisDataManager was not created!");
+
+  if (m_instance->m_mesh_id_mesh_polynomial_data_map.size() > 0) {
+    std::stringstream error;
+    error << ": some mesh data is still registered\n";
+    for (const auto& i_mesh_data : m_instance->m_mesh_id_mesh_polynomial_data_map) {
+      error << " - mesh data " << rang::fgB::magenta << i_mesh_data.first << rang::style::reset << '\n';
+    }
+    throw UnexpectedError(error.str());
+  }
+  delete m_instance;
+  m_instance = nullptr;
+}
+
+void
+PolynomialBasisDataManager::deletePolynomialBasisData(const size_t mesh_id)
+{
+  m_mesh_id_mesh_polynomial_data_map.erase(mesh_id);
+}
+
+template <MeshConcept MeshType>
+PolynomialBasisData<MeshType>&
+PolynomialBasisDataManager::getPolynomialBasisData(const MeshType& mesh)
+{
+  if (auto i_mesh_data = m_mesh_id_mesh_polynomial_data_map.find(mesh.id());
+      i_mesh_data != m_mesh_id_mesh_polynomial_data_map.end()) {
+    const auto& mesh_data_v = *i_mesh_data->second;
+    return *mesh_data_v.template get<MeshType>();
+  } else {
+    // **cannot** use make_shared since PolynomialBasisData constructor is **private**
+    std::shared_ptr<PolynomialBasisData<MeshType>> mesh_data{new PolynomialBasisData<MeshType>(mesh)};
+
+    m_mesh_id_mesh_polynomial_data_map[mesh.id()] = std::make_shared<PolynomialBasisDataVariant>(mesh_data);
+    return *mesh_data;
+  }
+}
+
+template PolynomialBasisData<Mesh<1>>& PolynomialBasisDataManager::getPolynomialBasisData(const Mesh<1>&);
+template PolynomialBasisData<Mesh<2>>& PolynomialBasisDataManager::getPolynomialBasisData(const Mesh<2>&);
+template PolynomialBasisData<Mesh<3>>& PolynomialBasisDataManager::getPolynomialBasisData(const Mesh<3>&);
diff --git a/src/scheme/PolynomialBasisDataManager.hpp b/src/scheme/PolynomialBasisDataManager.hpp
new file mode 100644
index 000000000..43b96dce8
--- /dev/null
+++ b/src/scheme/PolynomialBasisDataManager.hpp
@@ -0,0 +1,47 @@
+#ifndef POLYNOMIAL_BASIS_DATA_MANAGER_HPP
+#define POLYNOMIAL_BASIS_DATA_MANAGER_HPP
+
+#include <mesh/MeshTraits.hpp>
+#include <utils/PugsAssert.hpp>
+#include <utils/PugsMacros.hpp>
+
+#include <memory>
+#include <unordered_map>
+
+class PolynomialBasisDataVariant;
+
+template <MeshConcept MeshType>
+class PolynomialBasisData;
+
+class PolynomialBasisDataManager
+{
+ private:
+  std::unordered_map<size_t, std::shared_ptr<PolynomialBasisDataVariant>> m_mesh_id_mesh_polynomial_data_map;
+
+  static PolynomialBasisDataManager* m_instance;
+
+  PolynomialBasisDataManager(const PolynomialBasisDataManager&) = delete;
+  PolynomialBasisDataManager(PolynomialBasisDataManager&&)      = delete;
+
+  PolynomialBasisDataManager()  = default;
+  ~PolynomialBasisDataManager() = default;
+
+ public:
+  static void create();
+  static void destroy();
+
+  PUGS_INLINE
+  static PolynomialBasisDataManager&
+  instance()
+  {
+    Assert(m_instance != nullptr, "PolynomialBasisDataManager was not created!");
+    return *m_instance;
+  }
+
+  void deletePolynomialBasisData(const size_t mesh_id);
+
+  template <MeshConcept MeshType>
+  PolynomialBasisData<MeshType>& getPolynomialBasisData(const MeshType&);
+};
+
+#endif   // POLYNOMIAL_BASIS_DATA_MANAGER_HPP
diff --git a/src/scheme/PolynomialBasisDataVariant.hpp b/src/scheme/PolynomialBasisDataVariant.hpp
new file mode 100644
index 000000000..b713350b6
--- /dev/null
+++ b/src/scheme/PolynomialBasisDataVariant.hpp
@@ -0,0 +1,64 @@
+#ifndef POLYNOMIAL_BASIS_DATA_VARIANT_HPP
+#define POLYNOMIAL_BASIS_DATA_VARIANT_HPP
+
+#include <mesh/MeshTraits.hpp>
+#include <scheme/PolynomialBasisData.hpp>
+#include <utils/Demangle.hpp>
+#include <utils/Exceptions.hpp>
+#include <utils/PugsMacros.hpp>
+
+#include <rang.hpp>
+
+#include <memory>
+#include <sstream>
+#include <variant>
+
+template <size_t Dimension>
+class Mesh;
+
+class PolynomialBasisDataVariant
+{
+ private:
+  using Variant = std::variant<std::shared_ptr<PolynomialBasisData<Mesh<1>>>,   //
+                               std::shared_ptr<PolynomialBasisData<Mesh<2>>>,   //
+                               std::shared_ptr<PolynomialBasisData<Mesh<3>>>>;
+
+  Variant m_p_mesh_data_variant;
+
+ public:
+  template <MeshConcept MeshType>
+  PUGS_INLINE std::shared_ptr<PolynomialBasisData<MeshType>>
+  get() const
+  {
+    if (not std::holds_alternative<std::shared_ptr<PolynomialBasisData<MeshType>>>(this->m_p_mesh_data_variant)) {
+      std::ostringstream error_msg;
+      error_msg << "invalid mesh type type\n";
+      error_msg << "- required " << rang::fgB::red << demangle<PolynomialBasisData<MeshType>>() << rang::fg::reset
+                << '\n';
+      error_msg << "- contains " << rang::fgB::yellow
+                << std::visit(
+                     [](auto&& p_mesh_data) -> std::string {
+                       using FoundPolynomialBasisDataType = typename std::decay_t<decltype(p_mesh_data)>::element_type;
+                       return demangle<FoundPolynomialBasisDataType>();
+                     },
+                     this->m_p_mesh_data_variant)
+                << rang::fg::reset;
+      throw NormalError(error_msg.str());
+    }
+    return std::get<std::shared_ptr<PolynomialBasisData<MeshType>>>(m_p_mesh_data_variant);
+  }
+
+  PolynomialBasisDataVariant() = delete;
+
+  template <MeshConcept MeshType>
+  PolynomialBasisDataVariant(const std::shared_ptr<PolynomialBasisData<MeshType>>& p_mesh_data)
+    : m_p_mesh_data_variant{p_mesh_data}
+  {}
+
+  PolynomialBasisDataVariant(const PolynomialBasisDataVariant&) = default;
+  PolynomialBasisDataVariant(PolynomialBasisDataVariant&&)      = default;
+
+  ~PolynomialBasisDataVariant() = default;
+};
+
+#endif   // POLYNOMIAL_BASIS_DATA_VARIANT_HPP
diff --git a/tests/mpi_test_main.cpp b/tests/mpi_test_main.cpp
index cabb10386..36a28b131 100644
--- a/tests/mpi_test_main.cpp
+++ b/tests/mpi_test_main.cpp
@@ -9,6 +9,7 @@
 #include <mesh/MeshDataManager.hpp>
 #include <mesh/StencilManager.hpp>
 #include <mesh/SynchronizerManager.hpp>
+#include <scheme/PolynomialBasisDataManager.hpp>
 #include <utils/GlobalVariableManager.hpp>
 #include <utils/Messenger.hpp>
 #include <utils/PETScWrapper.hpp>
@@ -111,6 +112,7 @@ main(int argc, char* argv[])
       RandomEngine::create();
       QuadratureManager::create();
       MeshDataManager::create();
+      PolynomialBasisDataManager::create();
       DualConnectivityManager::create();
       DualMeshManager::create();
       StencilManager::create();
@@ -132,6 +134,7 @@ main(int argc, char* argv[])
       GlobalVariableManager::destroy();
       DualMeshManager::destroy();
       DualConnectivityManager::destroy();
+      PolynomialBasisDataManager::destroy();
       MeshDataManager::destroy();
       QuadratureManager::destroy();
       RandomEngine::destroy();
diff --git a/tests/test_main.cpp b/tests/test_main.cpp
index 98c01f787..83ff999d5 100644
--- a/tests/test_main.cpp
+++ b/tests/test_main.cpp
@@ -9,6 +9,7 @@
 #include <mesh/MeshDataManager.hpp>
 #include <mesh/StencilManager.hpp>
 #include <mesh/SynchronizerManager.hpp>
+#include <scheme/PolynomialBasisDataManager.hpp>
 #include <utils/GlobalVariableManager.hpp>
 #include <utils/Messenger.hpp>
 #include <utils/PETScWrapper.hpp>
@@ -66,6 +67,7 @@ main(int argc, char* argv[])
       RandomEngine::create();
       QuadratureManager::create();
       MeshDataManager::create();
+      PolynomialBasisDataManager::create();
       DualConnectivityManager::create();
       DualMeshManager::create();
       StencilManager::create();
@@ -87,6 +89,7 @@ main(int argc, char* argv[])
       StencilManager::destroy();
       DualMeshManager::destroy();
       DualConnectivityManager::destroy();
+      PolynomialBasisDataManager::destroy();
       MeshDataManager::destroy();
       QuadratureManager::destroy();
       RandomEngine::destroy();
-- 
GitLab