diff --git a/src/language/modules/SchemeModule.cpp b/src/language/modules/SchemeModule.cpp
index b9b789cfa8e3d7bc5328062c6085217dbe142120..6b775344aefb0a10e1c45b7df73bcd64bd5ba010 100644
--- a/src/language/modules/SchemeModule.cpp
+++ b/src/language/modules/SchemeModule.cpp
@@ -65,6 +65,9 @@
 #include <utils/checkpointing/WriteIQuadratureDescriptor.hpp>
 #include <utils/checkpointing/WriteVariableBCDescriptor.hpp>
 
+#warning remove
+#include <scheme/test_developed_reconstruction.hpp>
+
 #include <memory>
 
 SchemeModule::SchemeModule()
@@ -756,6 +759,17 @@ SchemeModule::SchemeModule()
 
                                               ));
 
+  this->_addBuiltinFunction("test_developed_reconstruction",
+                            std::function(
+
+                              [](const std::shared_ptr<const DiscreteFunctionVariant>& rho,
+                                 const std::shared_ptr<const DiscreteFunctionVariant>& u,
+                                 const std::shared_ptr<const DiscreteFunctionVariant>& E) -> void {
+                                test_developed_reconstruction(rho, u, E);
+                              }
+
+                              ));
+
   MathFunctionRegisterForVh{*this};
 }
 
diff --git a/src/scheme/CMakeLists.txt b/src/scheme/CMakeLists.txt
index 8c174aab69d2c588b143d316f24fc10357c36598..5ff646da8e42d42fa3e289158fd0bc0ce76c2e63 100644
--- a/src/scheme/CMakeLists.txt
+++ b/src/scheme/CMakeLists.txt
@@ -16,6 +16,8 @@ add_library(
   PolynomialBasisData.cpp
   PolynomialBasisDataManager.cpp
   PolynomialReconstruction.cpp
+
+  test_developed_reconstruction.cpp
 )
 
 target_link_libraries(
diff --git a/src/scheme/test_developed_reconstruction.cpp b/src/scheme/test_developed_reconstruction.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..6a4e4e6a030724dc671e90e534acb61c4d948b71
--- /dev/null
+++ b/src/scheme/test_developed_reconstruction.cpp
@@ -0,0 +1,967 @@
+#include <scheme/test_developed_reconstruction.hpp>
+
+#include <scheme/DiscreteFunctionDPkVariant.hpp>
+#include <scheme/DiscreteFunctionUtils.hpp>
+#include <scheme/PolynomialBasisData.hpp>
+#include <scheme/PolynomialBasisDataManager.hpp>
+#include <scheme/PolynomialReconstruction.hpp>
+#include <scheme/PolynomialReconstructionDescriptor.hpp>
+#include <utils/SmallArray.hpp>
+
+#include <analysis/GaussLegendreQuadratureDescriptor.hpp>
+#include <analysis/QuadratureManager.hpp>
+#include <geometry/LineTransformation.hpp>
+
+#include <fstream>
+
+template <MeshConcept MeshType, typename DataType>
+void computeFGBar(const std::shared_ptr<const MeshType>& p_mesh,
+                  const DiscreteFunctionDPk<MeshType::Dimension, const double>& f_bar,
+                  const DiscreteFunctionDPk<MeshType::Dimension, const DataType>& g_bar,
+                  DiscreteFunctionDPk<MeshType::Dimension, DataType>& fg_bar);
+
+template <typename DataType>
+void
+computeFGBar(const std::shared_ptr<const Mesh<1>>& p_mesh,
+             const DiscreteFunctionDPk<1, const double>& f_bar,
+             const DiscreteFunctionDPk<1, const DataType>& g_bar,
+             DiscreteFunctionDPk<1, DataType>& fg_bar)
+{
+  parallel_for(
+    p_mesh->numberOfCells(), PUGS_LAMBDA(const CellId cell_id) {
+      auto f_bar_coeffs  = f_bar.coefficients(cell_id);
+      auto g_bar_coeffs  = g_bar.coefficients(cell_id);
+      auto fg_bar_coeffs = fg_bar.coefficients(cell_id);
+
+      for (size_t i = 0; i < fg_bar_coeffs.size(); ++i) {
+        DataType sum;
+        if constexpr (std::is_arithmetic_v<DataType>) {
+          sum = 0;
+        } else {
+          sum = zero;
+        }
+        for (size_t i2 = 0; i2 <= i; ++i2) {
+          sum += f_bar_coeffs[i - i2] * g_bar_coeffs[i2];
+        }
+        fg_bar_coeffs[i] = sum;
+      }
+    });
+};
+
+template <typename DataType>
+void
+computeFGBar(const std::shared_ptr<const Mesh<2>>& p_mesh,
+             const DiscreteFunctionDPk<2, const double>& f_bar,
+             const DiscreteFunctionDPk<2, const DataType>& g_bar,
+             DiscreteFunctionDPk<2, DataType>& fg_bar)
+{
+  Assert((f_bar.degree() == g_bar.degree()) and (f_bar.degree() == fg_bar.degree()));
+  const size_t degree = f_bar.degree();
+
+  SmallArray<size_t> y_row_index(degree + 1);
+  {
+    size_t i_y = 0;
+
+    y_row_index[i_y++] = 0;
+    for (ssize_t n = degree + 1; n > 1; --n) {
+      y_row_index[i_y] = y_row_index[i_y - 1] + n;
+      ++i_y;
+    }
+  }
+  auto index = [&](size_t i, size_t j) { return y_row_index[j] + i; };
+
+  parallel_for(
+    p_mesh->numberOfCells(), PUGS_LAMBDA(const CellId cell_id) {
+      auto f_bar_coeffs  = f_bar.coefficients(cell_id);
+      auto g_bar_coeffs  = g_bar.coefficients(cell_id);
+      auto fg_bar_coeffs = fg_bar.coefficients(cell_id);
+
+      for (size_t j = 0; j <= degree; ++j) {
+        for (size_t i = 0; i <= degree - j; ++i) {
+          DataType sum;
+          if constexpr (std::is_arithmetic_v<DataType>) {
+            sum = 0;
+          } else {
+            sum = zero;
+          }
+
+          for (size_t j2 = 0; j2 <= j; ++j2) {
+            for (size_t i2 = 0; i2 <= i; ++i2) {
+              sum += f_bar_coeffs[index(i - i2, j - j2)] * g_bar_coeffs[index(i2, j2)];
+            }
+          }
+
+          fg_bar_coeffs[index(i, j)] = sum;
+        }
+      }
+    });
+}
+
+template <typename DataType>
+void
+computeFGBar(const std::shared_ptr<const Mesh<3>>& p_mesh,
+             const DiscreteFunctionDPk<3, const double>& f_bar,
+             const DiscreteFunctionDPk<3, const DataType>& g_bar,
+             DiscreteFunctionDPk<3, DataType>& fg_bar)
+{
+  Assert((f_bar.degree() == g_bar.degree()) and (f_bar.degree() == fg_bar.degree()));
+
+  const size_t degree = f_bar.degree();
+
+  SmallArray<size_t> yz_row_index((degree + 2) * (degree + 1) / 2 + 1);
+  SmallArray<size_t> z_triangle_index(degree + 1);
+
+  {
+    size_t i_z  = 0;
+    size_t i_yz = 0;
+
+    yz_row_index[i_yz++] = 0;
+    for (ssize_t n = degree + 1; n >= 1; --n) {
+      z_triangle_index[i_z++] = i_yz - 1;
+      for (ssize_t i = n; i >= 1; --i) {
+        yz_row_index[i_yz] = yz_row_index[i_yz - 1] + i;
+        ++i_yz;
+      }
+    }
+  }
+
+  SmallArray<size_t> yz_row_size{yz_row_index.size() - 1};
+  for (size_t i = 0; i < yz_row_size.size(); ++i) {
+    yz_row_size[i] = yz_row_index[i + 1] - yz_row_index[i];
+  }
+
+  auto index = [&](size_t i, size_t j, size_t k) { return yz_row_index[z_triangle_index[k] + j] + i; };
+
+  parallel_for(
+    p_mesh->numberOfCells(), PUGS_LAMBDA(const CellId cell_id) {
+      auto f_bar_coeffs  = f_bar.coefficients(cell_id);
+      auto g_bar_coeffs  = g_bar.coefficients(cell_id);
+      auto fg_bar_coeffs = fg_bar.coefficients(cell_id);
+
+      for (size_t k = 0; k <= degree; ++k) {
+        for (size_t j = 0; j <= degree - k; ++j) {
+          for (size_t i = 0; i <= degree - j - k; ++i) {
+            DataType sum;
+            if constexpr (std::is_arithmetic_v<DataType>) {
+              sum = 0;
+            } else {
+              sum = zero;
+            }
+
+            for (size_t k2 = 0; k2 <= k; ++k2) {
+              for (size_t j2 = 0; j2 <= j; ++j2) {
+                for (size_t i2 = 0; i2 <= i; ++i2) {
+                  sum += f_bar_coeffs[index(i - i2, j - j2, k - k2)] * g_bar_coeffs[index(i2, j2, k2)];
+                }
+              }
+            }
+
+            fg_bar_coeffs[index(i, j, k)] = sum;
+          }
+        }
+      }
+    });
+}
+
+template <MeshConcept MeshType, typename DataType>
+void computeKappaBar(const PolynomialReconstructionDescriptor descriptor,
+                     const std::shared_ptr<const MeshType>& p_mesh,
+                     const DiscreteFunctionDPk<MeshType::Dimension, const DataType>& u_bar,
+                     const DiscreteFunctionP0<const double>& kappa_j,
+                     DiscreteFunctionDPk<MeshType::Dimension, double>& kappa_bar);
+
+template <typename DataType>
+void
+computeKappaBar(const PolynomialReconstructionDescriptor descriptor,
+                const std::shared_ptr<const Mesh<1>>& p_mesh,
+                const DiscreteFunctionDPk<1, const DataType>& u_bar,
+                const DiscreteFunctionP0<const double>& kappa_j,
+                DiscreteFunctionDPk<1, double>& kappa_bar)
+{
+  auto polynomial_basis_means = PolynomialBasisDataManager::instance()
+                                  .getPolynomialBasisData(*p_mesh)
+                                  .getPolynomialBasisMeans(descriptor.integrationMethodType(), descriptor.degree());
+
+  parallel_for(
+    p_mesh->numberOfCells(), PUGS_LAMBDA(const CellId cell_id) {
+      auto u_bar_coeffs     = u_bar.coefficients(cell_id);
+      auto kappa_bar_coeffs = kappa_bar.coefficients(cell_id);
+      auto basis_means      = polynomial_basis_means[cell_id];
+
+      for (size_t i = 0; i < kappa_bar_coeffs.size(); ++i) {
+        double sum = 0;
+        for (size_t i2 = 0; i2 <= i; ++i2) {
+          sum += dot(u_bar_coeffs[i - i2], u_bar_coeffs[i2]);
+        }
+
+        kappa_bar_coeffs[i] = 0.5 * sum;
+      }
+
+      double kappa_bar_mean = 0;
+      for (size_t i = 0; i < basis_means.size(); ++i) {
+        kappa_bar_mean += basis_means[i] * kappa_bar_coeffs[i];
+      }
+
+      kappa_bar_coeffs[0] += kappa_j[cell_id] - kappa_bar_mean;
+    });
+}
+
+template <typename DataType>
+void
+computeKappaBar(const PolynomialReconstructionDescriptor descriptor,
+                const std::shared_ptr<const Mesh<2>>& p_mesh,
+                const DiscreteFunctionDPk<2, const DataType>& u_bar,
+                const DiscreteFunctionP0<const double>& kappa_j,
+                DiscreteFunctionDPk<2, double>& kappa_bar)
+{
+  Assert((u_bar.degree() == kappa_bar.degree()) and (u_bar.degree() == descriptor.degree()));
+  const size_t degree = descriptor.degree();
+
+  SmallArray<size_t> y_row_index(degree + 1);
+  {
+    size_t i_y = 0;
+
+    y_row_index[i_y++] = 0;
+    for (ssize_t n = degree + 1; n > 1; --n) {
+      y_row_index[i_y] = y_row_index[i_y - 1] + n;
+      ++i_y;
+    }
+  }
+  auto index = [&](size_t i, size_t j) { return y_row_index[j] + i; };
+
+  auto polynomial_basis_means = PolynomialBasisDataManager::instance()
+                                  .getPolynomialBasisData(*p_mesh)
+                                  .getPolynomialBasisMeans(descriptor.integrationMethodType(), descriptor.degree());
+
+  parallel_for(
+    p_mesh->numberOfCells(), PUGS_LAMBDA(const CellId cell_id) {
+      auto u_bar_coeffs     = u_bar.coefficients(cell_id);
+      auto kappa_bar_coeffs = kappa_bar.coefficients(cell_id);
+      auto basis_means      = polynomial_basis_means[cell_id];
+
+      for (size_t j = 0; j <= degree; ++j) {
+        for (size_t i = 0; i <= degree - j; ++i) {
+          double sum = 0;
+
+          for (size_t j2 = 0; j2 <= j; ++j2) {
+            for (size_t i2 = 0; i2 <= i; ++i2) {
+              sum += dot(u_bar_coeffs[index(i - i2, j - j2)], u_bar_coeffs[index(i2, j2)]);
+            }
+          }
+
+          kappa_bar_coeffs[index(i, j)] = 0.5 * sum;
+        }
+      }
+
+      double kappa_bar_mean = 0;
+      for (size_t i = 0; i < basis_means.size(); ++i) {
+        kappa_bar_mean += basis_means[i] * kappa_bar_coeffs[i];
+      }
+
+      kappa_bar_coeffs[0] += kappa_j[cell_id] - kappa_bar_mean;
+    });
+}
+
+template <typename DataType>
+void
+computeKappaBar(const PolynomialReconstructionDescriptor descriptor,
+                const std::shared_ptr<const Mesh<3>>& p_mesh,
+                const DiscreteFunctionDPk<3, const DataType>& u_bar,
+                const DiscreteFunctionP0<const double>& kappa_j,
+                DiscreteFunctionDPk<3, double>& kappa_bar)
+{
+  Assert((u_bar.degree() == kappa_bar.degree()) and (u_bar.degree() == descriptor.degree()));
+
+  const size_t degree = descriptor.degree();
+
+  SmallArray<size_t> yz_row_index((degree + 2) * (degree + 1) / 2 + 1);
+  SmallArray<size_t> z_triangle_index(degree + 1);
+
+  {
+    size_t i_z  = 0;
+    size_t i_yz = 0;
+
+    yz_row_index[i_yz++] = 0;
+    for (ssize_t n = degree + 1; n >= 1; --n) {
+      z_triangle_index[i_z++] = i_yz - 1;
+      for (ssize_t i = n; i >= 1; --i) {
+        yz_row_index[i_yz] = yz_row_index[i_yz - 1] + i;
+        ++i_yz;
+      }
+    }
+  }
+
+  SmallArray<size_t> yz_row_size{yz_row_index.size() - 1};
+  for (size_t i = 0; i < yz_row_size.size(); ++i) {
+    yz_row_size[i] = yz_row_index[i + 1] - yz_row_index[i];
+  }
+
+  auto index = [&](size_t i, size_t j, size_t k) { return yz_row_index[z_triangle_index[k] + j] + i; };
+
+  auto polynomial_basis_means = PolynomialBasisDataManager::instance()
+                                  .getPolynomialBasisData(*p_mesh)
+                                  .getPolynomialBasisMeans(descriptor.integrationMethodType(), descriptor.degree());
+
+  parallel_for(
+    p_mesh->numberOfCells(), PUGS_LAMBDA(const CellId cell_id) {
+      auto u_bar_coeffs     = u_bar.coefficients(cell_id);
+      auto kappa_bar_coeffs = kappa_bar.coefficients(cell_id);
+      auto basis_means      = polynomial_basis_means[cell_id];
+
+      for (size_t k = 0; k <= degree; ++k) {
+        for (size_t j = 0; j <= degree - k; ++j) {
+          for (size_t i = 0; i <= degree - j - k; ++i) {
+            double sum = 0;
+
+            for (size_t k2 = 0; k2 <= j; ++k2) {
+              for (size_t j2 = 0; j2 <= j; ++j2) {
+                for (size_t i2 = 0; i2 <= i; ++i2) {
+                  sum += dot(u_bar_coeffs[index(i - i2, j - j2, k - k2)], u_bar_coeffs[index(i2, j2, k2)]);
+                }
+              }
+            }
+
+            kappa_bar_coeffs[index(i, j, k)] = 0.5 * sum;
+          }
+        }
+      }
+
+      double kappa_bar_mean = 0;
+      for (size_t i = 0; i < basis_means.size(); ++i) {
+        kappa_bar_mean += basis_means[i] * kappa_bar_coeffs[i];
+      }
+
+      kappa_bar_coeffs[0] += kappa_j[cell_id] - kappa_bar_mean;
+    });
+}
+
+template <MeshConcept MeshType>
+void
+test_developed_reconstruction(const std::shared_ptr<const MeshType>& p_mesh,
+                              const std::shared_ptr<const DiscreteFunctionVariant>& rho_v,
+                              const std::shared_ptr<const DiscreteFunctionVariant>& u_v,
+                              const std::shared_ptr<const DiscreteFunctionVariant>& E_v)
+{
+  static constexpr size_t Dimension = MeshType::Dimension;
+  using Rd                          = TinyVector<Dimension>;
+  const size_t degree               = 2;
+
+  PolynomialReconstructionDescriptor descriptor{IntegrationMethodType::boundary, degree};
+
+  auto rho_h = rho_v->get<DiscreteFunctionP0<const double>>();
+  auto u_h   = u_v->get<DiscreteFunctionP0<const Rd>>();
+  auto E_h   = E_v->get<DiscreteFunctionP0<const double>>();
+
+  auto rho_E_h = rho_h * E_h;
+
+  DiscreteFunctionP0<double> kappa_h{p_mesh};
+  parallel_for(
+    p_mesh->numberOfCells(),
+    PUGS_LAMBDA(const CellId cell_id) { kappa_h[cell_id] = 0.5 * dot(u_h[cell_id], u_h[cell_id]); });
+
+  DiscreteFunctionP0<double> epsilon_h{p_mesh};
+  parallel_for(
+    p_mesh->numberOfCells(),
+    PUGS_LAMBDA(const CellId cell_id) { epsilon_h[cell_id] = E_h[cell_id] - kappa_h[cell_id]; });
+
+  auto reconstructions = PolynomialReconstruction{descriptor}.build(rho_v, u_v, epsilon_h, rho_E_h);
+
+  auto rho_E_bar = reconstructions[3]->get<DiscreteFunctionDPk<Dimension, const double>>();
+
+  auto polynomial_basis_means = PolynomialBasisDataManager::instance()
+                                  .getPolynomialBasisData(*p_mesh)
+                                  .getPolynomialBasisMeans(descriptor.integrationMethodType(), descriptor.degree());
+
+  auto remove_mean = [&](const auto& f_h, const auto& g_h, auto fg_bar) {
+    parallel_for(
+      p_mesh->numberOfCells(), PUGS_LAMBDA(const CellId cell_id) {
+        auto fg_bar_coeffs = fg_bar.coefficients(cell_id);
+        auto basis_means   = polynomial_basis_means[cell_id];
+        using DataType_fg  = std::decay_t<decltype(fg_bar_coeffs[0])>;
+
+        DataType_fg fg_bar_mean;
+        if constexpr (std::is_arithmetic_v<DataType_fg>) {
+          fg_bar_mean = 0;
+        } else {
+          fg_bar_mean = zero;
+        }
+
+        for (size_t i = 0; i < basis_means.size(); ++i) {
+          fg_bar_mean += basis_means[i] * fg_bar_coeffs[i];
+        }
+
+        fg_bar_coeffs[0] += f_h[cell_id] * g_h[cell_id] - fg_bar_mean;
+      });
+  };
+
+  auto compute_HP = [&](const auto& f_bar, const auto& fg_bar, const auto& g_h, auto& HP_fg) {
+    parallel_for(
+      p_mesh->numberOfCells(), PUGS_LAMBDA(const CellId cell_id) {
+        auto fg_bar_coeffs = fg_bar.coefficients(cell_id);
+        auto f_bar_coeffs  = f_bar.coefficients(cell_id);
+
+        auto HP_fg_coeffs = HP_fg.coefficients(cell_id);
+
+        const auto& gj = g_h[cell_id];
+
+        for (size_t i = 0; i < HP_fg_coeffs.size(); ++i) {
+          HP_fg_coeffs[i] = fg_bar_coeffs[i] - f_bar_coeffs[i] * gj;
+        }
+      });
+  };
+
+  auto rho_bar = reconstructions[0]->get<DiscreteFunctionDPk<Dimension, const double>>();
+  auto u_bar   = reconstructions[1]->get<DiscreteFunctionDPk<Dimension, const Rd>>();
+
+  DiscreteFunctionDPk<Dimension, Rd> rhou_bar{p_mesh, rho_bar.degree()};
+
+  computeFGBar(p_mesh, rho_bar, u_bar, rhou_bar);
+  // compute_fg_bar(rho_bar, u_bar, rhou_bar);
+  remove_mean(rho_h, u_h, rhou_bar);
+
+  DiscreteFunctionDPk<Dimension, Rd> HP_rhou{p_mesh, rho_bar.degree()};
+
+  compute_HP(rho_bar, rhou_bar, u_h, HP_rhou);
+
+  parallel_for(
+    p_mesh->numberOfCells(), PUGS_LAMBDA(const CellId cell_id) {
+      Rd HP_rhou_mean   = zero;
+      auto HP_fg_coeffs = HP_rhou.coefficients(cell_id);
+      auto basis_means  = polynomial_basis_means[cell_id];
+
+      for (size_t i = 0; i < basis_means.size(); ++i) {
+        HP_rhou_mean += basis_means[i] * HP_fg_coeffs[i];
+      }
+    });
+
+  auto u_bar_R = [&](const CellId cell_id, const Rd& x) {
+    return u_h[cell_id] + (1. / rho_bar[cell_id](x)) * HP_rhou[cell_id](x);
+  };
+
+  auto epsilon_bar = reconstructions[2]->get<DiscreteFunctionDPk<Dimension, const double>>();
+
+  DiscreteFunctionDPk<Dimension, double> rhoepsilon_bar{p_mesh, rho_bar.degree()};
+
+  computeFGBar(p_mesh, rho_bar, epsilon_bar, rhoepsilon_bar);
+  remove_mean(rho_h, epsilon_h, rhoepsilon_bar);
+
+  DiscreteFunctionDPk<Dimension, double> HP_rhoepsilon{p_mesh, rho_bar.degree()};
+
+  compute_HP(rho_bar, rhoepsilon_bar, epsilon_h, HP_rhoepsilon);
+
+  auto epsilon_bar_R = [&](const CellId cell_id, const Rd& x) {
+    return epsilon_h[cell_id] + (1. / rho_bar[cell_id](x)) * HP_rhoepsilon[cell_id](x);
+  };
+
+  DiscreteFunctionDPk<Dimension, const double> kappa_bar = [&] {
+    DiscreteFunctionDPk<Dimension, double> tmp_kappa_bar{p_mesh, rho_bar.degree()};
+    computeKappaBar(descriptor, p_mesh, u_bar, kappa_h, tmp_kappa_bar);
+    return tmp_kappa_bar;
+  }();
+
+  DiscreteFunctionDPk<Dimension, double> rhokappa_bar{p_mesh, rho_bar.degree()};
+
+  computeFGBar(p_mesh, rho_bar, kappa_bar, rhokappa_bar);
+  remove_mean(rho_h, kappa_h, rhokappa_bar);
+
+  DiscreteFunctionDPk<Dimension, double> HP_rhokappa{p_mesh, rho_bar.degree()};
+
+  compute_HP(rho_bar, rhokappa_bar, kappa_h, HP_rhokappa);
+
+  auto kappa_bar_R = [&](const CellId cell_id, const Rd& x) {
+    return kappa_h[cell_id] + (1. / rho_bar[cell_id](x)) * HP_rhokappa[cell_id](x);
+  };
+
+  auto epsilon_smile_R = [&](const CellId cell_id, const Rd& x) {
+    auto u_bar_R_x = u_bar_R(cell_id, x);
+    return epsilon_bar_R(cell_id, x) + kappa_bar_R(cell_id, x) - 0.5 * dot(u_bar_R_x, u_bar_R_x);
+  };
+
+  if constexpr (Dimension == 1) {
+    std::cout << "creating output...";
+    {
+      std::ofstream fout("comp-u");
+      fout.precision(15);
+      auto xr                  = p_mesh->xr();
+      auto cell_to_node_matrix = p_mesh->connectivity().cellToNodeMatrix();
+      for (CellId cell_id = 0; cell_id < p_mesh->numberOfCells(); ++cell_id) {
+        auto x0 = xr[cell_to_node_matrix[cell_id][0]];
+        auto x1 = xr[cell_to_node_matrix[cell_id][1]];
+        for (size_t i = 0; i <= 100; ++i) {
+          auto x = (1 - i / 100.) * x0 + i / 100. * x1;
+          fout << x[0] << ' ' << u_bar[cell_id](x)[0] << ' ' << u_bar_R(cell_id, x)[0] << '\n';
+        }
+        fout << "\n\n";
+      }
+    }
+    {
+      std::ofstream fout("comp-epsilon");
+      fout.precision(15);
+      auto xr                  = p_mesh->xr();
+      auto cell_to_node_matrix = p_mesh->connectivity().cellToNodeMatrix();
+      for (CellId cell_id = 0; cell_id < p_mesh->numberOfCells(); ++cell_id) {
+        auto x0 = xr[cell_to_node_matrix[cell_id][0]];
+        auto x1 = xr[cell_to_node_matrix[cell_id][1]];
+        for (size_t i = 0; i <= 100; ++i) {
+          auto x = (1 - i / 100.) * x0 + i / 100. * x1;
+          fout << x[0] << ' ' << epsilon_bar[cell_id](x) << ' ' << epsilon_bar_R(cell_id, x) << ' '
+               << epsilon_smile_R(cell_id, x) << '\n';
+        }
+        fout << "\n\n";
+      }
+    }
+    {
+      std::ofstream fout("comp-epsilon");
+      fout.precision(15);
+      auto xr                  = p_mesh->xr();
+      auto cell_to_node_matrix = p_mesh->connectivity().cellToNodeMatrix();
+      for (CellId cell_id = 0; cell_id < p_mesh->numberOfCells(); ++cell_id) {
+        auto x0 = xr[cell_to_node_matrix[cell_id][0]];
+        auto x1 = xr[cell_to_node_matrix[cell_id][1]];
+        for (size_t i = 0; i <= 100; ++i) {
+          auto x = (1 - i / 100.) * x0 + i / 100. * x1;
+          fout << x[0] << ' ' << epsilon_bar[cell_id](x) << ' ' << epsilon_bar_R(cell_id, x) << ' '
+               << epsilon_smile_R(cell_id, x) << '\n';
+        }
+        fout << "\n\n";
+      }
+    }
+
+    {
+      std::ofstream fout("comp-rho_E");
+      fout.precision(15);
+      auto xr                  = p_mesh->xr();
+      auto cell_to_node_matrix = p_mesh->connectivity().cellToNodeMatrix();
+      for (CellId cell_id = 0; cell_id < p_mesh->numberOfCells(); ++cell_id) {
+        auto x0 = xr[cell_to_node_matrix[cell_id][0]];
+        auto x1 = xr[cell_to_node_matrix[cell_id][1]];
+        for (size_t i = 0; i <= 100; ++i) {
+          auto x = (1 - i / 100.) * x0 + i / 100. * x1;
+          fout << x[0] << ' ' << rho_E_bar[cell_id](x) << ' '
+               << rho_bar[cell_id](x) *
+                    (epsilon_smile_R(cell_id, x) + 0.5 * dot(u_bar_R(cell_id, x), u_bar_R(cell_id, x)))
+               << '\n';
+        }
+        fout << "\n\n";
+      }
+    }
+
+    std::cout << "done\n";
+
+    if constexpr (Dimension == 1) {
+      auto xr                  = p_mesh->xr();
+      auto cell_to_node_matrix = p_mesh->connectivity().cellToNodeMatrix();
+
+      double sum = 0;
+      auto qf    = QuadratureManager::instance().getLineFormula(GaussLegendreQuadratureDescriptor{10});
+      for (CellId cell_id = 0; cell_id < p_mesh->numberOfCells(); ++cell_id) {
+        LineTransformation<Dimension> t{xr[cell_to_node_matrix[cell_id][0]], xr[cell_to_node_matrix[cell_id][1]]};
+        for (size_t i_q = 0; i_q < qf.numberOfPoints(); ++i_q) {
+          auto x = t(qf.point(i_q));
+          sum +=
+            std::abs(qf.weight(i_q) * (rho_E_bar[cell_id](x) -
+                                       rho_bar[cell_id](x) * (epsilon_smile_R(cell_id, x) +
+                                                              0.5 * dot(u_bar_R(cell_id, x), u_bar_R(cell_id, x)))));
+        }
+      }
+
+      std::cout << "L1 error = " << sum << '\n';
+    }
+  }
+}
+
+template <MeshConcept MeshType>
+void
+test_developed_reconstruction2(const std::shared_ptr<const MeshType>& p_mesh,
+                               const std::shared_ptr<const DiscreteFunctionVariant>& rho_v,
+                               const std::shared_ptr<const DiscreteFunctionVariant>& u_v,
+                               const std::shared_ptr<const DiscreteFunctionVariant>& E_v)
+{
+  static constexpr size_t Dimension = MeshType::Dimension;
+  using Rd                          = TinyVector<Dimension>;
+  const size_t degree               = 3;
+
+  PolynomialReconstructionDescriptor descriptor{IntegrationMethodType::boundary, degree};
+
+  auto rho_h = rho_v->get<DiscreteFunctionP0<const double>>();
+  auto u_h   = u_v->get<DiscreteFunctionP0<const Rd>>();
+  auto E_h   = E_v->get<DiscreteFunctionP0<const double>>();
+
+  auto rho_E_h = rho_h * E_h;
+
+  DiscreteFunctionP0<double> kappa_h{p_mesh};
+  parallel_for(
+    p_mesh->numberOfCells(),
+    PUGS_LAMBDA(const CellId cell_id) { kappa_h[cell_id] = 0.5 * dot(u_h[cell_id], u_h[cell_id]); });
+
+  DiscreteFunctionP0<double> epsilon_h{p_mesh};
+  parallel_for(
+    p_mesh->numberOfCells(),
+    PUGS_LAMBDA(const CellId cell_id) { epsilon_h[cell_id] = E_h[cell_id] - kappa_h[cell_id]; });
+
+  auto rho_epsilon_h = rho_h * epsilon_h;
+  auto rho_kappa_h   = rho_h * kappa_h;
+  auto rho_u_h       = rho_h * u_h;
+
+  auto reconstructions =
+    PolynomialReconstruction{descriptor}.build(rho_v, rho_u_h, rho_epsilon_h, rho_kappa_h, rho_E_h, epsilon_h, u_v);
+
+  auto rho_bar         = reconstructions[0]->template get<DiscreteFunctionDPk<Dimension, const double>>();
+  auto rho_u_bar       = reconstructions[1]->template get<DiscreteFunctionDPk<Dimension, const Rd>>();
+  auto rho_epsilon_bar = reconstructions[2]->template get<DiscreteFunctionDPk<Dimension, const double>>();
+  auto rho_kappa_bar   = reconstructions[3]->template get<DiscreteFunctionDPk<Dimension, const double>>();
+  auto rho_E_bar       = reconstructions[4]->template get<DiscreteFunctionDPk<Dimension, const double>>();
+  auto epsilon_bar     = reconstructions[5]->template get<DiscreteFunctionDPk<Dimension, const double>>();
+  auto u_bar           = reconstructions[6]->template get<DiscreteFunctionDPk<Dimension, const Rd>>();
+
+  auto polynomial_basis_means = PolynomialBasisDataManager::instance()
+                                  .getPolynomialBasisData(*p_mesh)
+                                  .getPolynomialBasisMeans(descriptor.integrationMethodType(), descriptor.degree());
+
+  auto remove_mean = [&](const auto& f_h, const auto& g_h, auto fg_bar) {
+    parallel_for(
+      p_mesh->numberOfCells(), PUGS_LAMBDA(const CellId cell_id) {
+        auto fg_bar_coeffs = fg_bar.coefficients(cell_id);
+        auto basis_means   = polynomial_basis_means[cell_id];
+        using DataType_fg  = std::decay_t<decltype(fg_bar_coeffs[0])>;
+
+        DataType_fg fg_bar_mean;
+        if constexpr (std::is_arithmetic_v<DataType_fg>) {
+          fg_bar_mean = 0;
+        } else {
+          fg_bar_mean = zero;
+        }
+
+        for (size_t i = 0; i < basis_means.size(); ++i) {
+          fg_bar_mean += basis_means[i] * fg_bar_coeffs[i];
+        }
+
+        fg_bar_coeffs[0] += f_h[cell_id] * g_h[cell_id] - fg_bar_mean;
+      });
+  };
+
+  auto compute_HP = [&](const auto& f_bar, const auto& fg_bar, const auto& g_h, auto& HP_fg) {
+    parallel_for(
+      p_mesh->numberOfCells(), PUGS_LAMBDA(const CellId cell_id) {
+        auto fg_bar_coeffs = fg_bar.coefficients(cell_id);
+        auto f_bar_coeffs  = f_bar.coefficients(cell_id);
+
+        auto HP_fg_coeffs = HP_fg.coefficients(cell_id);
+
+        const auto& gj = g_h[cell_id];
+
+        for (size_t i = 0; i < HP_fg_coeffs.size(); ++i) {
+          HP_fg_coeffs[i] = fg_bar_coeffs[i] - f_bar_coeffs[i] * gj;
+        }
+      });
+  };
+
+  // auto rho_bar = reconstructions[0]->get<DiscreteFunctionDPk<Dimension, const double>>();
+  // auto u_bar   = reconstructions[1]->get<DiscreteFunctionDPk<Dimension, const Rd>>();
+
+  // DiscreteFunctionDPk<Dimension, Rd> rhou_bar{p_mesh, rho_bar.degree()};
+
+  // computeFGBar(p_mesh, rho_bar, u_bar, rhou_bar);
+  // compute_fg_bar(rho_bar, u_bar, rhou_bar);
+  // remove_mean(rho_h, u_h, rhou_bar);
+
+  DiscreteFunctionDPk<Dimension, Rd> HP_rhou{p_mesh, rho_bar.degree()};
+
+  compute_HP(rho_bar, rho_u_bar, u_h, HP_rhou);
+
+  // parallel_for(
+  //   p_mesh->numberOfCells(), PUGS_LAMBDA(const CellId cell_id) {
+  //     Rd HP_rhou_mean   = zero;
+  //     auto HP_fg_coeffs = HP_rhou.coefficients(cell_id);
+  //     auto basis_means  = polynomial_basis_means[cell_id];
+
+  //     for (size_t i = 0; i < basis_means.size(); ++i) {
+  //       HP_rhou_mean += basis_means[i] * HP_fg_coeffs[i];
+  //     }
+  //   });
+
+  auto u_bar_R = [&](const CellId cell_id, const Rd& x) {
+    return u_h[cell_id] + (1. / rho_bar[cell_id](x)) * HP_rhou[cell_id](x);
+  };
+
+  // auto epsilon_bar = reconstructions[2]->get<DiscreteFunctionDPk<Dimension, const double>>();
+
+  // DiscreteFunctionDPk<Dimension, double> rhoepsilon_bar{p_mesh, rho_bar.degree()};
+
+  // computeFGBar(p_mesh, rho_bar, epsilon_bar, rhoepsilon_bar);
+  // remove_mean(rho_h, epsilon_h, rhoepsilon_bar);
+
+  DiscreteFunctionDPk<Dimension, double> HP_rhoepsilon{p_mesh, rho_bar.degree()};
+
+  compute_HP(rho_bar, rho_epsilon_bar, epsilon_h, HP_rhoepsilon);
+
+  auto epsilon_bar_R = [&](const CellId cell_id, const Rd& x) {
+    return epsilon_h[cell_id] + (1. / rho_bar[cell_id](x)) * HP_rhoepsilon[cell_id](x);
+  };
+
+  // DiscreteFunctionDPk<Dimension, const double> kappa_bar = [&] {
+  //   DiscreteFunctionDPk<Dimension, double> tmp_kappa_bar{p_mesh, rho_bar.degree()};
+  //   computeKappaBar(descriptor, p_mesh, u_bar, kappa_h, tmp_kappa_bar);
+  //   return tmp_kappa_bar;
+  // }();
+
+  // DiscreteFunctionDPk<Dimension, double> rhokappa_bar{p_mesh, rho_bar.degree()};
+
+  // computeFGBar(p_mesh, rho_bar, kappa_bar, rhokappa_bar);
+  // remove_mean(rho_h, kappa_h, rhokappa_bar);
+
+  DiscreteFunctionDPk<Dimension, double> HP_rhokappa{p_mesh, rho_bar.degree()};
+
+  compute_HP(rho_bar, rho_kappa_bar, kappa_h, HP_rhokappa);
+
+  auto kappa_bar_R = [&](const CellId cell_id, const Rd& x) {
+    return kappa_h[cell_id] + (1. / rho_bar[cell_id](x)) * HP_rhokappa[cell_id](x);
+  };
+
+  auto epsilon_smile_R = [&](const CellId cell_id, const Rd& x) {
+    auto u_bar_R_x = u_bar_R(cell_id, x);
+    return epsilon_bar_R(cell_id, x) + kappa_bar_R(cell_id, x) - 0.5 * dot(u_bar_R_x, u_bar_R_x);
+  };
+
+  if constexpr (Dimension == 1) {
+    std::cout << "creating output...";
+    {
+      std::ofstream fout("comp-u");
+      fout.precision(15);
+      auto xr                  = p_mesh->xr();
+      auto cell_to_node_matrix = p_mesh->connectivity().cellToNodeMatrix();
+      for (CellId cell_id = 0; cell_id < p_mesh->numberOfCells(); ++cell_id) {
+        auto x0 = xr[cell_to_node_matrix[cell_id][0]];
+        auto x1 = xr[cell_to_node_matrix[cell_id][1]];
+        for (size_t i = 0; i <= 100; ++i) {
+          auto x = (1 - i / 100.) * x0 + i / 100. * x1;
+          fout << x[0] << ' ' << u_bar[cell_id](x)[0] << ' ' << u_bar_R(cell_id, x)[0] << '\n';
+        }
+        fout << "\n\n";
+      }
+    }
+    {
+      std::ofstream fout("comp-epsilon");
+      fout.precision(15);
+      auto xr                  = p_mesh->xr();
+      auto cell_to_node_matrix = p_mesh->connectivity().cellToNodeMatrix();
+      for (CellId cell_id = 0; cell_id < p_mesh->numberOfCells(); ++cell_id) {
+        auto x0 = xr[cell_to_node_matrix[cell_id][0]];
+        auto x1 = xr[cell_to_node_matrix[cell_id][1]];
+        for (size_t i = 0; i <= 100; ++i) {
+          auto x = (1 - i / 100.) * x0 + i / 100. * x1;
+          fout << x[0] << ' ' << epsilon_bar[cell_id](x) << ' ' << epsilon_bar_R(cell_id, x) << ' '
+               << epsilon_smile_R(cell_id, x) << '\n';
+        }
+        fout << "\n\n";
+      }
+    }
+    {
+      std::ofstream fout("comp-epsilon");
+      fout.precision(15);
+      auto xr                  = p_mesh->xr();
+      auto cell_to_node_matrix = p_mesh->connectivity().cellToNodeMatrix();
+      for (CellId cell_id = 0; cell_id < p_mesh->numberOfCells(); ++cell_id) {
+        auto x0 = xr[cell_to_node_matrix[cell_id][0]];
+        auto x1 = xr[cell_to_node_matrix[cell_id][1]];
+        for (size_t i = 0; i <= 100; ++i) {
+          auto x = (1 - i / 100.) * x0 + i / 100. * x1;
+          fout << x[0] << ' ' << epsilon_bar[cell_id](x) << ' ' << epsilon_bar_R(cell_id, x) << ' '
+               << epsilon_smile_R(cell_id, x) << '\n';
+        }
+        fout << "\n\n";
+      }
+    }
+
+    {
+      std::ofstream fout("comp-rho_E");
+      fout.precision(15);
+      auto xr                  = p_mesh->xr();
+      auto cell_to_node_matrix = p_mesh->connectivity().cellToNodeMatrix();
+      for (CellId cell_id = 0; cell_id < p_mesh->numberOfCells(); ++cell_id) {
+        auto x0 = xr[cell_to_node_matrix[cell_id][0]];
+        auto x1 = xr[cell_to_node_matrix[cell_id][1]];
+        for (size_t i = 0; i <= 100; ++i) {
+          auto x = (1 - i / 100.) * x0 + i / 100. * x1;
+          fout << x[0] << ' ' << rho_E_bar[cell_id](x) << ' '
+               << rho_bar[cell_id](x) *
+                    (epsilon_smile_R(cell_id, x) + 0.5 * dot(u_bar_R(cell_id, x), u_bar_R(cell_id, x)))
+               << '\n';
+        }
+        fout << "\n\n";
+      }
+    }
+
+    std::cout << "done\n";
+
+    if constexpr (Dimension == 1) {
+      auto xr                  = p_mesh->xr();
+      auto cell_to_node_matrix = p_mesh->connectivity().cellToNodeMatrix();
+
+      double sum = 0;
+      auto qf    = QuadratureManager::instance().getLineFormula(GaussLegendreQuadratureDescriptor{10});
+      for (CellId cell_id = 0; cell_id < p_mesh->numberOfCells(); ++cell_id) {
+        LineTransformation<Dimension> t{xr[cell_to_node_matrix[cell_id][0]], xr[cell_to_node_matrix[cell_id][1]]};
+        for (size_t i_q = 0; i_q < qf.numberOfPoints(); ++i_q) {
+          auto x = t(qf.point(i_q));
+          sum +=
+            std::abs(qf.weight(i_q) * (rho_E_bar[cell_id](x) -
+                                       rho_bar[cell_id](x) * (epsilon_smile_R(cell_id, x) +
+                                                              0.5 * dot(u_bar_R(cell_id, x), u_bar_R(cell_id, x)))));
+        }
+      }
+
+      std::cout << "L1 error = " << sum << '\n';
+    }
+  }
+}
+
+template <MeshConcept MeshType>
+void
+test_developed_reconstruction3(const std::shared_ptr<const MeshType>& p_mesh,
+                               const std::shared_ptr<const DiscreteFunctionVariant>& rho_v,
+                               const std::shared_ptr<const DiscreteFunctionVariant>& u_v,
+                               const std::shared_ptr<const DiscreteFunctionVariant>& E_v)
+{
+  static constexpr size_t Dimension = MeshType::Dimension;
+  using Rd                          = TinyVector<Dimension>;
+  const size_t degree               = 3;
+
+  PolynomialReconstructionDescriptor descriptor{IntegrationMethodType::boundary, degree};
+
+  auto rho_h = rho_v->get<DiscreteFunctionP0<const double>>();
+  auto u_h   = u_v->get<DiscreteFunctionP0<const Rd>>();
+  auto E_h   = E_v->get<DiscreteFunctionP0<const double>>();
+
+  auto rho_u_h = rho_h * u_h;
+  auto rho_E_h = rho_h * E_h;
+
+  auto reconstructions = PolynomialReconstruction{descriptor}.build(rho_v, u_v, rho_u_h);
+
+  auto rho_u_bar_cons = reconstructions[2]->template get<DiscreteFunctionDPk<Dimension, const Rd>>();
+
+  auto polynomial_basis_means = PolynomialBasisDataManager::instance()
+                                  .getPolynomialBasisData(*p_mesh)
+                                  .getPolynomialBasisMeans(descriptor.integrationMethodType(), descriptor.degree());
+
+  auto remove_mean = [&](const auto& f_h, const auto& g_h, auto fg_bar) {
+    parallel_for(
+      p_mesh->numberOfCells(), PUGS_LAMBDA(const CellId cell_id) {
+        auto fg_bar_coeffs = fg_bar.coefficients(cell_id);
+        auto basis_means   = polynomial_basis_means[cell_id];
+        using DataType_fg  = std::decay_t<decltype(fg_bar_coeffs[0])>;
+
+        DataType_fg fg_bar_mean;
+        if constexpr (std::is_arithmetic_v<DataType_fg>) {
+          fg_bar_mean = 0;
+        } else {
+          fg_bar_mean = zero;
+        }
+
+        for (size_t i = 0; i < basis_means.size(); ++i) {
+          fg_bar_mean += basis_means[i] * fg_bar_coeffs[i];
+        }
+
+        fg_bar_coeffs[0] += f_h[cell_id] * g_h[cell_id] - fg_bar_mean;
+      });
+  };
+
+  auto compute_HP = [&](const auto& f_bar, const auto& fg_bar, const auto& g_h, auto& HP_fg) {
+    parallel_for(
+      p_mesh->numberOfCells(), PUGS_LAMBDA(const CellId cell_id) {
+        auto fg_bar_coeffs = fg_bar.coefficients(cell_id);
+        auto f_bar_coeffs  = f_bar.coefficients(cell_id);
+
+        auto HP_fg_coeffs = HP_fg.coefficients(cell_id);
+
+        const auto& gj = g_h[cell_id];
+
+        for (size_t i = 0; i < HP_fg_coeffs.size(); ++i) {
+          HP_fg_coeffs[i] = fg_bar_coeffs[i] - f_bar_coeffs[i] * gj;
+        }
+      });
+  };
+
+  auto rho_bar_cons = reconstructions[0]->template get<DiscreteFunctionDPk<Dimension, const double>>();
+  auto u_bar_cons   = reconstructions[1]->template get<DiscreteFunctionDPk<Dimension, const Rd>>();
+
+  DiscreteFunctionDPk<Dimension, const double> rho_bar = [&] {
+    auto v = copy(rho_bar_cons);
+    parallel_for(
+      p_mesh->numberOfCells(), PUGS_LAMBDA(const CellId cell_id) {
+        auto v_coeffs = v.coefficients(cell_id);
+        v_coeffs[0]   = rho_h[cell_id];
+      });
+    return v;
+  }();
+
+  DiscreteFunctionDPk<Dimension, const Rd> u_bar = [&] {
+    auto v = copy(u_bar_cons);
+    parallel_for(
+      p_mesh->numberOfCells(), PUGS_LAMBDA(const CellId cell_id) {
+        auto u_bar_coeffs = v.coefficients(cell_id);
+        u_bar_coeffs[0]   = u_h[cell_id];
+      });
+    return v;
+  }();
+
+  DiscreteFunctionDPk<Dimension, Rd> rhou_bar{p_mesh, rho_bar.degree()};
+
+  computeFGBar(p_mesh, rho_bar, u_bar, rhou_bar);
+  remove_mean(rho_h, u_h, rhou_bar);
+
+  DiscreteFunctionDPk<Dimension, Rd> HP_rhou{p_mesh, rho_bar.degree()};
+
+  compute_HP(rho_bar_cons, rhou_bar, u_h, HP_rhou);
+
+  auto u_bar_R = [&](const CellId cell_id, const Rd& x) {
+    return u_h[cell_id] + (1. / rho_bar_cons[cell_id](x)) * HP_rhou[cell_id](x);
+  };
+
+  if constexpr (Dimension == 1) {
+    std::cout << "done\n";
+
+    if constexpr (Dimension == 1) {
+      auto xr                  = p_mesh->xr();
+      auto cell_to_node_matrix = p_mesh->connectivity().cellToNodeMatrix();
+
+      {
+        double sum = 0;
+        auto qf    = QuadratureManager::instance().getLineFormula(GaussLegendreQuadratureDescriptor{10});
+        for (CellId cell_id = 0; cell_id < p_mesh->numberOfCells(); ++cell_id) {
+          LineTransformation<Dimension> t{xr[cell_to_node_matrix[cell_id][0]], xr[cell_to_node_matrix[cell_id][1]]};
+          for (size_t i_q = 0; i_q < qf.numberOfPoints(); ++i_q) {
+            auto x    = t(qf.point(i_q));
+            auto diff = (rho_u_bar_cons[cell_id](x) - rhou_bar[cell_id](x));
+            sum += std::abs(qf.weight(i_q) * std::abs(diff[0]));
+          }
+        }
+        std::cout << "rho u: L1 error = " << sum << '\n';
+      }
+
+      // {
+      //   double sum = 0;
+      //   auto qf    = QuadratureManager::instance().getLineFormula(GaussLegendreQuadratureDescriptor{10});
+      //   for (CellId cell_id = 0; cell_id < p_mesh->numberOfCells(); ++cell_id) {
+      //     LineTransformation<Dimension> t{xr[cell_to_node_matrix[cell_id][0]], xr[cell_to_node_matrix[cell_id][1]]};
+      //     for (size_t i_q = 0; i_q < qf.numberOfPoints(); ++i_q) {
+      //       auto x    = t(qf.point(i_q));
+      //       auto diff = (rho_u_bar_cons[cell_id](x) - rho_bar_cons[cell_id](x) * (u_bar_R(cell_id, x)));
+      //       sum += std::abs(qf.weight(i_q) * std::abs(diff[0]));
+      //     }
+      //   }
+      //   std::cout << "rho u: L1 error = " << sum << '\n';
+      // }
+    }
+  }
+}
+
+void
+test_developed_reconstruction(const std::shared_ptr<const DiscreteFunctionVariant>& rho_v,
+                              const std::shared_ptr<const DiscreteFunctionVariant>& u_v,
+                              const std::shared_ptr<const DiscreteFunctionVariant>& E_v)
+{
+  auto mesh_v = getCommonMesh({rho_v, u_v, E_v});
+
+  std::visit([&](auto&& p_mesh) { test_developed_reconstruction3(p_mesh, rho_v, u_v, E_v); }, mesh_v->variant());
+}
diff --git a/src/scheme/test_developed_reconstruction.hpp b/src/scheme/test_developed_reconstruction.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..625506fbe605702c4cb200650b341f3ec6d5f62f
--- /dev/null
+++ b/src/scheme/test_developed_reconstruction.hpp
@@ -0,0 +1,10 @@
+#ifndef TEST_DEVELOPED_RECONSTRUCTION_HPP
+#define TEST_DEVELOPED_RECONSTRUCTION_HPP
+
+#include <scheme/DiscreteFunctionVariant.hpp>
+
+void test_developed_reconstruction(const std::shared_ptr<const DiscreteFunctionVariant>& rho_v,
+                                   const std::shared_ptr<const DiscreteFunctionVariant>& u_v,
+                                   const std::shared_ptr<const DiscreteFunctionVariant>& E_v);
+
+#endif   // TEST_DEVELOPED_RECONSTRUCTION_HPP