From ac8db537eddf0bd37dbeb1f45841a9ee6c2cc949 Mon Sep 17 00:00:00 2001
From: Tobias Leibner <tobias.leibner@googlemail.com>
Date: Mon, 15 Jul 2019 15:43:40 +0200
Subject: [PATCH] move momentmodels folder to test

---
 dune/gdt/local/numerical-fluxes/kinetic.hh    |   4 +-
 dune/gdt/operators/reconstruction/slopes.hh   |   4 +-
 .../test/entropic-coords-mn-discretization.hh |   8 +-
 dune/gdt/test/mn-discretization.hh            |   2 +-
 .../{ => test}/momentmodels/basisfunctions.hh |   0
 .../basisfunctions/hatfunctions.hh            |   2 +-
 .../momentmodels/basisfunctions/interface.hh  |   2 +-
 .../momentmodels/basisfunctions/legendre.hh   |   0
 .../basisfunctions/partial_moments.hh         |   0
 .../basisfunctions/spherical_harmonics.hh     |   0
 .../momentmodels/density_evaluations.hh       |   2 +-
 .../{ => test}/momentmodels/entropyflux.hh    |   4 +-
 .../entropyflux_implementations.hh            |   2 +-
 .../momentmodels/entropyflux_kineticcoords.hh |   6 +-
 .../{ => test}/momentmodels/entropysolver.hh  |   2 +-
 .../momentmodels/hessianinverter.hh           |   2 +-
 .../momentmodels/kinetictransport/base.hh     |   4 +-
 .../kinetictransport/testcases.hh             |   2 +-
 .../test/momentmodels/moment-approximation.hh | 427 ++++++++++++++++++
 .../{ => test}/momentmodels/triangulation.hh  |   0
 dune/gdt/type_traits.hh                       |   4 +-
 21 files changed, 452 insertions(+), 25 deletions(-)
 rename dune/gdt/{ => test}/momentmodels/basisfunctions.hh (100%)
 rename dune/gdt/{ => test}/momentmodels/basisfunctions/hatfunctions.hh (99%)
 rename dune/gdt/{ => test}/momentmodels/basisfunctions/interface.hh (99%)
 rename dune/gdt/{ => test}/momentmodels/basisfunctions/legendre.hh (100%)
 rename dune/gdt/{ => test}/momentmodels/basisfunctions/partial_moments.hh (100%)
 rename dune/gdt/{ => test}/momentmodels/basisfunctions/spherical_harmonics.hh (100%)
 rename dune/gdt/{ => test}/momentmodels/density_evaluations.hh (99%)
 rename dune/gdt/{ => test}/momentmodels/entropyflux.hh (99%)
 rename dune/gdt/{ => test}/momentmodels/entropyflux_implementations.hh (99%)
 rename dune/gdt/{ => test}/momentmodels/entropyflux_kineticcoords.hh (98%)
 rename dune/gdt/{ => test}/momentmodels/entropysolver.hh (99%)
 rename dune/gdt/{ => test}/momentmodels/hessianinverter.hh (99%)
 create mode 100644 dune/gdt/test/momentmodels/moment-approximation.hh
 rename dune/gdt/{ => test}/momentmodels/triangulation.hh (100%)

diff --git a/dune/gdt/local/numerical-fluxes/kinetic.hh b/dune/gdt/local/numerical-fluxes/kinetic.hh
index bbd0564c9..04a4daaa0 100644
--- a/dune/gdt/local/numerical-fluxes/kinetic.hh
+++ b/dune/gdt/local/numerical-fluxes/kinetic.hh
@@ -13,8 +13,8 @@
 
 #include <dune/xt/la/container.hh>
 
-#include <dune/gdt/momentmodels/basisfunctions.hh>
-#include <dune/gdt/momentmodels/entropyflux.hh>
+#include <dune/gdt/test/momentmodels/basisfunctions.hh>
+#include <dune/gdt/test/momentmodels/entropyflux.hh>
 
 #include "interface.hh"
 
diff --git a/dune/gdt/operators/reconstruction/slopes.hh b/dune/gdt/operators/reconstruction/slopes.hh
index 3d884adfc..15c461b94 100644
--- a/dune/gdt/operators/reconstruction/slopes.hh
+++ b/dune/gdt/operators/reconstruction/slopes.hh
@@ -28,8 +28,8 @@
 #include <dune/xt/common/fvector.hh>
 #include <dune/xt/common/parallel/threadstorage.hh>
 
-#include <dune/gdt/momentmodels/basisfunctions/partial_moments.hh>
-#include <dune/gdt/momentmodels/entropyflux.hh>
+#include <dune/gdt/test/momentmodels/basisfunctions/partial_moments.hh>
+#include <dune/gdt/test/momentmodels/entropyflux.hh>
 
 namespace Dune {
 namespace GDT {
diff --git a/dune/gdt/test/entropic-coords-mn-discretization.hh b/dune/gdt/test/entropic-coords-mn-discretization.hh
index 753f61235..1b8e4f374 100644
--- a/dune/gdt/test/entropic-coords-mn-discretization.hh
+++ b/dune/gdt/test/entropic-coords-mn-discretization.hh
@@ -25,10 +25,10 @@
 #include <dune/gdt/operators/generic.hh>
 #include <dune/gdt/operators/reconstruction/linear_kinetic.hh>
 #include <dune/gdt/interpolations/default.hh>
-#include <dune/gdt/momentmodels/hessianinverter.hh>
-#include <dune/gdt/momentmodels/entropyflux_kineticcoords.hh>
-#include <dune/gdt/momentmodels/entropyflux.hh>
-#include <dune/gdt/momentmodels/density_evaluations.hh>
+#include <dune/gdt/test/momentmodels/hessianinverter.hh>
+#include <dune/gdt/test/momentmodels/entropyflux_kineticcoords.hh>
+#include <dune/gdt/test/momentmodels/entropyflux.hh>
+#include <dune/gdt/test/momentmodels/density_evaluations.hh>
 #include <dune/gdt/local/numerical-fluxes/kinetic.hh>
 #include <dune/gdt/local/operators/advection-fv.hh>
 #include <dune/gdt/spaces/l2/finite-volume.hh>
diff --git a/dune/gdt/test/mn-discretization.hh b/dune/gdt/test/mn-discretization.hh
index 4ca091065..5df56da73 100644
--- a/dune/gdt/test/mn-discretization.hh
+++ b/dune/gdt/test/mn-discretization.hh
@@ -23,7 +23,7 @@
 #include <dune/gdt/operators/advection-fv-entropybased.hh>
 #include <dune/gdt/operators/advection-fv.hh>
 #include <dune/gdt/interpolations/default.hh>
-#include <dune/gdt/momentmodels/entropysolver.hh>
+#include <dune/gdt/test/momentmodels/entropysolver.hh>
 #include <dune/gdt/local/numerical-fluxes/kinetic.hh>
 #include <dune/gdt/local/operators/advection-fv.hh>
 #include <dune/gdt/spaces/l2/finite-volume.hh>
diff --git a/dune/gdt/momentmodels/basisfunctions.hh b/dune/gdt/test/momentmodels/basisfunctions.hh
similarity index 100%
rename from dune/gdt/momentmodels/basisfunctions.hh
rename to dune/gdt/test/momentmodels/basisfunctions.hh
diff --git a/dune/gdt/momentmodels/basisfunctions/hatfunctions.hh b/dune/gdt/test/momentmodels/basisfunctions/hatfunctions.hh
similarity index 99%
rename from dune/gdt/momentmodels/basisfunctions/hatfunctions.hh
rename to dune/gdt/test/momentmodels/basisfunctions/hatfunctions.hh
index b9aebac16..c40825ef5 100644
--- a/dune/gdt/momentmodels/basisfunctions/hatfunctions.hh
+++ b/dune/gdt/test/momentmodels/basisfunctions/hatfunctions.hh
@@ -16,7 +16,7 @@
 
 #include <dune/xt/common/fmatrix.hh>
 
-#include <dune/gdt/momentmodels/triangulation.hh>
+#include <dune/gdt/test/momentmodels/triangulation.hh>
 
 #include "interface.hh"
 
diff --git a/dune/gdt/momentmodels/basisfunctions/interface.hh b/dune/gdt/test/momentmodels/basisfunctions/interface.hh
similarity index 99%
rename from dune/gdt/momentmodels/basisfunctions/interface.hh
rename to dune/gdt/test/momentmodels/basisfunctions/interface.hh
index 6d959c4f7..70564ac74 100644
--- a/dune/gdt/momentmodels/basisfunctions/interface.hh
+++ b/dune/gdt/test/momentmodels/basisfunctions/interface.hh
@@ -22,7 +22,7 @@
 #include <dune/xt/data/spherical_quadratures.hh>
 
 #include <dune/gdt/discretefunction/default.hh>
-#include <dune/gdt/momentmodels/triangulation.hh>
+#include <dune/gdt/test/momentmodels/triangulation.hh>
 
 namespace Dune {
 namespace GDT {
diff --git a/dune/gdt/momentmodels/basisfunctions/legendre.hh b/dune/gdt/test/momentmodels/basisfunctions/legendre.hh
similarity index 100%
rename from dune/gdt/momentmodels/basisfunctions/legendre.hh
rename to dune/gdt/test/momentmodels/basisfunctions/legendre.hh
diff --git a/dune/gdt/momentmodels/basisfunctions/partial_moments.hh b/dune/gdt/test/momentmodels/basisfunctions/partial_moments.hh
similarity index 100%
rename from dune/gdt/momentmodels/basisfunctions/partial_moments.hh
rename to dune/gdt/test/momentmodels/basisfunctions/partial_moments.hh
diff --git a/dune/gdt/momentmodels/basisfunctions/spherical_harmonics.hh b/dune/gdt/test/momentmodels/basisfunctions/spherical_harmonics.hh
similarity index 100%
rename from dune/gdt/momentmodels/basisfunctions/spherical_harmonics.hh
rename to dune/gdt/test/momentmodels/basisfunctions/spherical_harmonics.hh
diff --git a/dune/gdt/momentmodels/density_evaluations.hh b/dune/gdt/test/momentmodels/density_evaluations.hh
similarity index 99%
rename from dune/gdt/momentmodels/density_evaluations.hh
rename to dune/gdt/test/momentmodels/density_evaluations.hh
index 113589e67..c3827d7a2 100644
--- a/dune/gdt/momentmodels/density_evaluations.hh
+++ b/dune/gdt/test/momentmodels/density_evaluations.hh
@@ -17,7 +17,7 @@
 #include <dune/xt/common/parameter.hh>
 
 #include <dune/gdt/discretefunction/default.hh>
-#include <dune/gdt/momentmodels/entropyflux_kineticcoords.hh>
+#include <dune/gdt/test/momentmodels/entropyflux_kineticcoords.hh>
 #include <dune/gdt/operators/interfaces.hh>
 #include <dune/gdt/type_traits.hh>
 
diff --git a/dune/gdt/momentmodels/entropyflux.hh b/dune/gdt/test/momentmodels/entropyflux.hh
similarity index 99%
rename from dune/gdt/momentmodels/entropyflux.hh
rename to dune/gdt/test/momentmodels/entropyflux.hh
index d81860778..f9658b412 100644
--- a/dune/gdt/momentmodels/entropyflux.hh
+++ b/dune/gdt/test/momentmodels/entropyflux.hh
@@ -21,8 +21,8 @@
 
 #include <dune/xt/functions/interfaces/flux-function.hh>
 
-#include <dune/gdt/momentmodels/basisfunctions.hh>
-#include <dune/gdt/momentmodels/entropyflux_implementations.hh>
+#include <dune/gdt/test/momentmodels/basisfunctions.hh>
+#include <dune/gdt/test/momentmodels/entropyflux_implementations.hh>
 
 namespace Dune {
 namespace GDT {
diff --git a/dune/gdt/momentmodels/entropyflux_implementations.hh b/dune/gdt/test/momentmodels/entropyflux_implementations.hh
similarity index 99%
rename from dune/gdt/momentmodels/entropyflux_implementations.hh
rename to dune/gdt/test/momentmodels/entropyflux_implementations.hh
index b964d10d5..974a036fb 100644
--- a/dune/gdt/momentmodels/entropyflux_implementations.hh
+++ b/dune/gdt/test/momentmodels/entropyflux_implementations.hh
@@ -40,7 +40,7 @@
 
 #include <dune/xt/functions/interfaces/function.hh>
 
-#include <dune/gdt/momentmodels/basisfunctions.hh>
+#include <dune/gdt/test/momentmodels/basisfunctions.hh>
 #include <dune/gdt/type_traits.hh>
 
 #include "config.h"
diff --git a/dune/gdt/momentmodels/entropyflux_kineticcoords.hh b/dune/gdt/test/momentmodels/entropyflux_kineticcoords.hh
similarity index 98%
rename from dune/gdt/momentmodels/entropyflux_kineticcoords.hh
rename to dune/gdt/test/momentmodels/entropyflux_kineticcoords.hh
index 6db77042b..02852a3e6 100644
--- a/dune/gdt/momentmodels/entropyflux_kineticcoords.hh
+++ b/dune/gdt/test/momentmodels/entropyflux_kineticcoords.hh
@@ -18,9 +18,9 @@
 
 #include <dune/xt/functions/interfaces/flux-function.hh>
 
-#include <dune/gdt/momentmodels/basisfunctions.hh>
-#include <dune/gdt/momentmodels/entropyflux_implementations.hh>
-#include <dune/gdt/momentmodels/entropyflux.hh>
+#include <dune/gdt/test/momentmodels/basisfunctions.hh>
+#include <dune/gdt/test/momentmodels/entropyflux_implementations.hh>
+#include <dune/gdt/test/momentmodels/entropyflux.hh>
 
 namespace Dune {
 namespace GDT {
diff --git a/dune/gdt/momentmodels/entropysolver.hh b/dune/gdt/test/momentmodels/entropysolver.hh
similarity index 99%
rename from dune/gdt/momentmodels/entropysolver.hh
rename to dune/gdt/test/momentmodels/entropysolver.hh
index 1c16194b2..c3b34d0e6 100644
--- a/dune/gdt/momentmodels/entropysolver.hh
+++ b/dune/gdt/test/momentmodels/entropysolver.hh
@@ -16,7 +16,7 @@
 #include <dune/xt/common/parameter.hh>
 
 #include <dune/gdt/discretefunction/default.hh>
-#include <dune/gdt/momentmodels/entropyflux.hh>
+#include <dune/gdt/test/momentmodels/entropyflux.hh>
 #include <dune/gdt/operators/interfaces.hh>
 #include <dune/gdt/type_traits.hh>
 
diff --git a/dune/gdt/momentmodels/hessianinverter.hh b/dune/gdt/test/momentmodels/hessianinverter.hh
similarity index 99%
rename from dune/gdt/momentmodels/hessianinverter.hh
rename to dune/gdt/test/momentmodels/hessianinverter.hh
index c37eeb041..b3b6fee38 100644
--- a/dune/gdt/momentmodels/hessianinverter.hh
+++ b/dune/gdt/test/momentmodels/hessianinverter.hh
@@ -16,7 +16,7 @@
 #include <dune/xt/common/parameter.hh>
 
 #include <dune/gdt/discretefunction/default.hh>
-#include <dune/gdt/momentmodels/entropyflux_kineticcoords.hh>
+#include <dune/gdt/test/momentmodels/entropyflux_kineticcoords.hh>
 #include <dune/gdt/operators/interfaces.hh>
 #include <dune/gdt/type_traits.hh>
 
diff --git a/dune/gdt/test/momentmodels/kinetictransport/base.hh b/dune/gdt/test/momentmodels/kinetictransport/base.hh
index 9367a38d5..0a5239f6f 100644
--- a/dune/gdt/test/momentmodels/kinetictransport/base.hh
+++ b/dune/gdt/test/momentmodels/kinetictransport/base.hh
@@ -17,8 +17,8 @@
 
 #include <dune/xt/la/solver.hh>
 
-#include <dune/gdt/momentmodels/basisfunctions.hh>
-#include <dune/gdt/momentmodels/entropyflux.hh>
+#include <dune/gdt/test/momentmodels/basisfunctions.hh>
+#include <dune/gdt/test/momentmodels/entropyflux.hh>
 #include <dune/gdt/test/momentmodels/kineticequation.hh>
 
 #include "../kineticequation.hh"
diff --git a/dune/gdt/test/momentmodels/kinetictransport/testcases.hh b/dune/gdt/test/momentmodels/kinetictransport/testcases.hh
index 260a26d5a..f16229a02 100644
--- a/dune/gdt/test/momentmodels/kinetictransport/testcases.hh
+++ b/dune/gdt/test/momentmodels/kinetictransport/testcases.hh
@@ -13,7 +13,7 @@
 
 #include <dune/grid/yaspgrid.hh>
 
-#include <dune/gdt/momentmodels/basisfunctions.hh>
+#include <dune/gdt/test/momentmodels/basisfunctions.hh>
 #include <dune/gdt/spaces/l2/finite-volume.hh>
 #include <dune/gdt/spaces/l2/discontinuous-lagrange.hh>
 #include <dune/gdt/tools/timestepper/interface.hh>
diff --git a/dune/gdt/test/momentmodels/moment-approximation.hh b/dune/gdt/test/momentmodels/moment-approximation.hh
new file mode 100644
index 000000000..967a1c7d9
--- /dev/null
+++ b/dune/gdt/test/momentmodels/moment-approximation.hh
@@ -0,0 +1,427 @@
+// This file is part of the dune-gdt project:
+//   https://github.com/dune-community/dune-gdt
+// Copyright 2010-2016 dune-gdt developers and contributors. All rights reserved.
+// License: BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)
+// Authors:
+//   Tobias Leibner  (2016)
+
+#ifndef DUNE_GDT_TEST_HYPERBOLIC_MOMENT_APPROXIMATION_HH
+#define DUNE_GDT_TEST_HYPERBOLIC_MOMENT_APPROXIMATION_HH
+
+#include <chrono>
+#include <fstream>
+
+#include <dune/xt/common/string.hh>
+
+#include <dune/xt/data/quadratures/fekete.hh>
+
+#include <dune/xt/grid/gridprovider.hh>
+
+#include <dune/xt/la/container.hh>
+
+#include <dune/gdt/type_traits.hh>
+#include <dune/gdt/test/momentmodels/entropyflux.hh>
+
+namespace Dune {
+namespace GDT {
+
+
+bool is_empty(const std::string filename)
+{
+  std::ifstream file(filename);
+  return !file.good() || file.peek() == std::ifstream::traits_type::eof();
+}
+
+template <class MomentBasisType, class DiscreteFunctionType>
+struct MomentApproximation
+{
+  using SpaceType = typename DiscreteFunctionType::SpaceType;
+  using GridViewType = typename SpaceType::GridViewType;
+  using GridType = typename GridViewType::Grid;
+  using DomainType = typename MomentBasisType::DomainType;
+  using RangeFieldType = typename DiscreteFunctionType::RangeFieldType;
+  using DynamicRangeType = typename MomentBasisType::DynamicRangeType;
+  using QuadraturesType = typename MomentBasisType::QuadraturesType;
+  static const size_t dimDomain = MomentBasisType::dimDomain;
+  static const size_t dimRange = MomentBasisType::dimRange;
+
+  // Chooses the quadrature that is used to calculate l1, l2, linf error and do the visualization
+  // In 1d, we use a Gauss-Lobatto-Quadrature of order 197 (100 quadrature points) on each interval. For the
+  // fullmoments, we fix the number of intervals to 50. Thus we have a different quadrature for each model, but the high
+  // order of the quadratures should ensure that the quadrature error is negligible compared to the model error.
+  // Choosing a fixed quadrature for all models would not allow to align the quadrature to the interval boundaries,
+  // which potentially causes much higher errors especially in linf norm. In 3d, all spherical triangles are refinements
+  // of the initial octants, so we can use the same quadrature (on the finest triangulation) for all models. Note that
+  // this quadrature is not used for the optimization problems in the entropy-based models. For the optimization
+  // problems, we use the following model-adapted quadratures: PMM_n and HFM_n (1d): A Gauss-Lobatto quadrature of order
+  // 15 on each interval. M_N (1d): A Gauss-Lobatto quadrature of order 197 on each of the intervals [-1,0] and [0,1].
+  // PMM_n and HFM_n (3d): A Fekete quadrature of order 9 on each spherical triangle (order 15 for PMM_32 and HFM_6).
+  // M_N (3d): A product quadrature of order 2N+8 on the octants of the sphere.
+  template <size_t domainDim = dimDomain, bool anything = true>
+  struct QuadratureHelper;
+
+  template <bool anything>
+  struct QuadratureHelper<3, anything>
+  {
+    static std::unique_ptr<SphericalTriangulation<RangeFieldType>> create_triangulation()
+    {
+      return std::make_unique<SphericalTriangulation<RangeFieldType>>(MomentBasisType::num_refinements);
+    }
+
+    static QuadraturesType get(const SphericalTriangulation<RangeFieldType>& triangulation,
+                               const int quadrature_refinements,
+                               const bool visualization,
+                               const int /*additional_refs*/)
+    {
+      QuadratureRule<RangeFieldType, 2> reference_quadrature_rule =
+          XT::Data::FeketeQuadrature<RangeFieldType>::get(visualization ? 1 : 9);
+      const int additional_refs = quadrature_refinements - static_cast<int>(MomentBasisType::num_refinements);
+      if (additional_refs < 0)
+        DUNE_THROW(InvalidStateException,
+                   "The number of refinements for the quadrature has to be greater or equal than the number of "
+                   "refinements the basisfunctions use!");
+      return triangulation.quadrature_rules(static_cast<size_t>(additional_refs), reference_quadrature_rule);
+    }
+  };
+
+  template <bool anything>
+  struct QuadratureHelper<1, anything>
+  {
+    static std::unique_ptr<SphericalTriangulation<RangeFieldType>> create_triangulation()
+    {
+      return std::make_unique<SphericalTriangulation<RangeFieldType>>();
+    }
+
+    static QuadraturesType get(const SphericalTriangulation<RangeFieldType>& /*triangulation*/,
+                               const int num_quadrature_intervals,
+                               const bool /*visualization*/,
+                               const int additional_refs)
+    {
+      return MomentBasisType::gauss_lobatto_quadratures(num_quadrature_intervals, 197, additional_refs);
+    }
+  };
+
+  // use block-wise solver for 3d partial moments, sparse solver for full matrix otherwise
+  template <bool partialmoments = is_3d_partial_moment_basis<MomentBasisType>::value, bool anything = true>
+  struct SolverHelper;
+
+  template <bool anything>
+  struct SolverHelper<true, anything>
+  {
+    static void solve(const MomentBasisType& basis_functions, const DynamicRangeType& u, DynamicRangeType& pn_coeffs)
+    {
+      const auto mass_matrix = basis_functions.block_mass_matrix();
+      FieldVector<double, 4> local_coeffs;
+      FieldVector<double, 4> local_u;
+      for (size_t jj = 0; jj < mass_matrix->num_rows / 4; ++jj) {
+        for (size_t kk = 0; kk < 4; ++kk)
+          local_u[kk] = u[4 * jj + kk];
+        mass_matrix->block(jj).solve(local_coeffs, local_u);
+        for (size_t kk = 0; kk < 4; ++kk)
+          pn_coeffs[4 * jj + kk] = local_coeffs[kk];
+      }
+    }
+  };
+
+  template <bool anything>
+  struct SolverHelper<false, anything>
+  {
+    static void solve(const MomentBasisType& basis_functions, const DynamicRangeType& u, DynamicRangeType& pn_coeffs)
+    {
+      const auto mass_matrix = basis_functions.mass_matrix();
+      XT::LA::IstlRowMajorSparseMatrix<double> sparse_mass_matrix(mass_matrix, true);
+      XT::LA::IstlDenseVector<double> pn_coeffs_istl(sparse_mass_matrix.rows());
+      XT::LA::IstlDenseVector<double> u_istl(pn_coeffs_istl);
+      for (size_t ii = 0; ii < u_istl.size(); ++ii)
+        u_istl.set_entry(ii, u[ii]);
+      XT::LA::solve(sparse_mass_matrix, u_istl, pn_coeffs_istl);
+      for (size_t ii = 0; ii < pn_coeffs_istl.size(); ++ii)
+        pn_coeffs[ii] = pn_coeffs_istl.get_entry(ii);
+    }
+  };
+
+  static void run(const int quad_refinements, std::string testcase, std::string filename = "")
+  {
+    //******************* create grid and basisfunctions ***************************************
+    auto grid_config = Dune::XT::Grid::cube_gridprovider_default_config();
+    const auto grid_provider =
+        Dune::XT::Grid::CubeGridProviderFactory<GridType>::create(grid_config, MPIHelper::getCommunicator());
+    const auto grid_view = grid_provider.leaf_view();
+
+    // ***************** choose testcase *********************
+    RangeFieldType tau = 1e-9;
+    RangeFieldType additional_quad_refinements =
+        (dimDomain == 1 && quad_refinements < 50) ? std::ceil(std::log2(50. / quad_refinements)) : 0.;
+    std::function<RangeFieldType(const DomainType&, const bool)> psi;
+    if (testcase == "Heaviside") {
+      if (dimDomain != 1)
+        DUNE_THROW(InvalidStateException,
+                   "This is a 1-dimensional test, but the basis functions are " + XT::Common::to_string(dimDomain)
+                       + "-dimensional!");
+      psi = [](const DomainType& v, const bool left) {
+        return v[0] < 0 || (XT::Common::is_zero(v[0]) && left) ? RangeFieldType(5e-9) : RangeFieldType(1);
+      };
+    } else if (testcase == "HeavisideUnfitted") {
+      if (dimDomain != 1)
+        DUNE_THROW(InvalidStateException,
+                   "This is a 1-dimensional test, but the basis functions are " + XT::Common::to_string(dimDomain)
+                       + "-dimensional!");
+      psi = [](const DomainType& v, const bool /*left*/) {
+        return v[0] < 1. / M_PI ? RangeFieldType(5e-9) : RangeFieldType(1);
+      };
+    } else if (testcase == "Gauss1d") {
+      tau = 1e-12;
+      if (dimDomain != 1)
+        DUNE_THROW(InvalidStateException,
+                   "This is a 1-dimensional test, but the basis functions are " + XT::Common::to_string(dimDomain)
+                       + "-dimensional!");
+      const RangeFieldType sigma = 0.5;
+      const RangeFieldType mu = 0.;
+      psi = [sigma, mu](const DomainType& v, const bool) {
+        return 1. / std::sqrt(2. * M_PI * std::pow(sigma, 2))
+               * std::exp(std::pow(v[0] - mu, 2) / (-2 * std::pow(sigma, 2)));
+      };
+    } else if (testcase == "CrossingBeams1dSmooth") {
+      if (dimDomain != 1)
+        DUNE_THROW(InvalidStateException,
+                   "This is a 1-dimensional test, but the basis functions are " + XT::Common::to_string(dimDomain)
+                       + "-dimensional!");
+      const RangeFieldType factor = 1e5;
+      const RangeFieldType norm = std::sqrt(M_PI / factor);
+      psi = [factor, norm](const DomainType& v, const bool) {
+        return std::max((std::exp(-factor * std::pow(v[0] - 1, 2)) + std::exp(-factor * std::pow(v[0] + 1, 2))) / norm,
+                        5e-9);
+      };
+    } else if (testcase == "CrossingBeams1dSmooth_2") {
+      if (dimDomain != 1)
+        DUNE_THROW(InvalidStateException,
+                   "This is a 1-dimensional test, but the basis functions are " + XT::Common::to_string(dimDomain)
+                       + "-dimensional!");
+      const RangeFieldType factor = 1e5;
+      const RangeFieldType norm = std::sqrt(M_PI / factor);
+      psi = [factor, norm](const DomainType& v, const bool) {
+        return std::max(
+            (std::exp(-factor * std::pow(v[0] - 0.5, 2)) + std::exp(-factor * std::pow(v[0] + 1, 2))) / norm, 5e-9);
+      };
+    } else if (testcase == "CrossingBeams1dDiscontinuous") {
+      if (dimDomain != 1)
+        DUNE_THROW(InvalidStateException,
+                   "This is a 1-dimensional test, but the basis functions are " + XT::Common::to_string(dimDomain)
+                       + "-dimensional!");
+      psi = [](const DomainType& v, const bool) {
+        RangeFieldType height = 100;
+        if (std::abs(v[0] + 1) < 1. / (2 * height) || std::abs(v[0] - 1) < 1. / (2 * height))
+          return height;
+        else
+          return 5e-9;
+      };
+    } else if (testcase == "CrossingBeams1dDiscontinuous_2") {
+      if (dimDomain != 1)
+        DUNE_THROW(InvalidStateException,
+                   "This is a 1-dimensional test, but the basis functions are " + XT::Common::to_string(dimDomain)
+                       + "-dimensional!");
+      psi = [](const DomainType& v, const bool) {
+        RangeFieldType height = 100;
+        if (std::abs(v[0] + 1) < 1. / (2 * height) || std::abs(v[0] - 0.5) < 1. / (2 * height))
+          return height;
+        else
+          return 5e-9;
+      };
+    } else if (testcase == "GaussOnSphere") {
+      tau = 1e-12;
+      if (dimDomain != 3)
+        DUNE_THROW(InvalidStateException,
+                   "This is a 3-dimensional test, but the basis functions are " + XT::Common::to_string(dimDomain)
+                       + "-dimensional!");
+      const RangeFieldType sigma = 0.5;
+      const RangeFieldType mu = 1.;
+      psi = [sigma, mu](const DomainType& v, const bool) {
+        return 1. / (2. * M_PI * std::pow(sigma, 2) * (1. - std::exp(-2 / std::pow(sigma, 2))))
+               * std::exp((std::pow(v[0] - mu, 2) + std::pow(v[1], 2) + std::pow(v[2], 2)) / (-2 * std::pow(sigma, 2)));
+      };
+    } else if (testcase == "SquareOnSphere") {
+      if (dimDomain != 3)
+        DUNE_THROW(InvalidStateException,
+                   "This is a 3-dimensional test, but the basis functions are " + XT::Common::to_string(dimDomain)
+                       + "-dimensional!");
+      psi = [](const DomainType& v, const bool) {
+        if (v[0] > 0 && std::abs(v[1]) < 0.5 && std::abs(v[2]) < 0.5)
+          return RangeFieldType(1);
+        else
+          return RangeFieldType(1e-8 / (4 * M_PI));
+      };
+    } else if (testcase == "CrossingBeams3d") {
+      if (dimDomain != 3)
+        DUNE_THROW(InvalidStateException,
+                   "This is a 3-dimensional test, but the basis functions are " + XT::Common::to_string(dimDomain)
+                       + "-dimensional!");
+      const RangeFieldType factor = 1e2;
+      const RangeFieldType norm = M_PI / factor;
+      const FieldVector<RangeFieldType, 3> center1{{1., 0., 0.}};
+      const FieldVector<RangeFieldType, 3> center2{{0., 1., 0.}};
+      psi = [factor, norm, center1, center2](const DomainType& v, const bool) {
+        return std::max((std::exp(-factor * (v - center1).two_norm2()) + std::exp(-factor * (v - center2).two_norm2()))
+                            / norm,
+                        1e-8 / (4 * M_PI));
+      };
+    } else if (testcase == "CrossingBeams3d_2") {
+      if (dimDomain != 3)
+        DUNE_THROW(InvalidStateException,
+                   "This is a 3-dimensional test, but the basis functions are " + XT::Common::to_string(dimDomain)
+                       + "-dimensional!");
+      const RangeFieldType factor = 1e2;
+      const RangeFieldType norm = M_PI / factor;
+      const FieldVector<RangeFieldType, 3> center1{{std::sqrt(1. / 3.), std::sqrt(1. / 3.), std::sqrt(1. / 3.)}};
+      const FieldVector<RangeFieldType, 3> center2{
+          {std::sqrt(1. / (2 * M_PI)), -std::sqrt(0.5 - 1. / (4 * M_PI)), std::sqrt(0.5 - 1. / (4 * M_PI))}};
+      psi = [factor, norm, center1, center2](const DomainType& v, const bool) {
+        return std::max((std::exp(-factor * (v - center1).two_norm2()) + std::exp(-factor * (v - center2).two_norm2()))
+                            / norm,
+                        1e-8 / (4 * M_PI));
+      };
+    } else if (testcase == "CrossingBeams3dDiscontinuous") {
+      if (dimDomain != 3)
+        DUNE_THROW(InvalidStateException,
+                   "This is a 3-dimensional test, but the basis functions are " + XT::Common::to_string(dimDomain)
+                       + "-dimensional!");
+      const FieldVector<RangeFieldType, 3> center1{{std::sqrt(1. / 3.), std::sqrt(1. / 3.), std::sqrt(1. / 3.)}};
+      const FieldVector<RangeFieldType, 3> center2{
+          {std::sqrt(1. / (2 * M_PI)), -std::sqrt(0.5 - 1. / (4 * M_PI)), std::sqrt(0.5 - 1. / (4 * M_PI))}};
+      const RangeFieldType r = 0.1;
+      const RangeFieldType r_squared = std::pow(r, 2);
+      psi = [r_squared, center1, center2](const DomainType& v, const bool) {
+        if ((v - center1).two_norm2() < r_squared || (v - center2).two_norm2() < r_squared)
+          return 1 / (M_PI * r_squared);
+        else
+          return 1e-8 / (4 * M_PI);
+      };
+    } else {
+      DUNE_THROW(NotImplemented, "Unknown testcase " + testcase + "!");
+    }
+
+    //******************* choose quadrature that is used for visualization and error calculation *******************
+    auto begin = std::chrono::steady_clock::now();
+    const auto triangulation = QuadratureHelper<>::create_triangulation();
+    std::chrono::duration<double> time = std::chrono::steady_clock::now() - begin;
+    if (dimDomain == 3)
+      std::cout << "Creating triangulation took: " << time.count() << " s!" << std::endl;
+    begin = std::chrono::steady_clock::now();
+    const auto visualization_quadratures =
+        QuadratureHelper<>::get(*triangulation, quad_refinements, true, additional_quad_refinements);
+    const auto basis_quadratures =
+        QuadratureHelper<>::get(*triangulation, quad_refinements, false, additional_quad_refinements);
+    time = std::chrono::steady_clock::now() - begin;
+    std::cout << "Creating quadratures took: " << time.count() << " s!" << std::endl;
+    begin = std::chrono::steady_clock::now();
+    std::shared_ptr<const MomentBasisType> basis_functions =
+        std::make_shared<const MomentBasisType>(*triangulation, basis_quadratures);
+    time = std::chrono::steady_clock::now() - begin;
+    std::cout << "Creating basis functions took: " << time.count() << " s!" << std::endl;
+
+    begin = std::chrono::steady_clock::now();
+    const auto u = basis_functions->get_moment_vector(psi);
+    time = std::chrono::steady_clock::now() - begin;
+    std::cout << "Calculating u took: " << time.count() << " s!" << std::endl;
+    using MnFluxType = EntropyBasedFluxFunction<GridViewType, MomentBasisType>;
+    begin = std::chrono::steady_clock::now();
+    MnFluxType mn_flux(grid_view,
+                       *basis_functions,
+                       tau,
+                       true,
+                       0.01,
+                       0.5,
+                       1e-3,
+                       {0, 1e-8, 1e-6, 1e-4, 1e-3, 1e-2, 5e-2, 0.1, 0.5, 1},
+                       50,
+                       100);
+    std::cout << "Creating entropy flux took: "
+              << std::chrono::duration_cast<std::chrono::seconds>(std::chrono::steady_clock::now() - begin).count()
+              << "s!" << std::endl;
+    const auto mn_begin = std::chrono::steady_clock::now();
+    const auto mn_ret = mn_flux.get_alpha(u, true);
+    const auto mn_end = std::chrono::steady_clock::now();
+    const std::chrono::duration<double> mn_time = mn_end - mn_begin;
+    std::cout << "Mn solve took: " << mn_time.count() << " s!" << std::endl;
+
+    const auto alpha = mn_ret->first;
+
+    const auto entropy_string =
+        "_"
+        + std::string(MomentBasisType::entropy == EntropyType::MaxwellBoltzmann ? "MaxwellBoltzmann" : "BoseEinstein")
+        + "_";
+    const auto filename_mn = filename + entropy_string + basis_functions->mn_name();
+    const auto filename_pn = filename + "_" + basis_functions->pn_name();
+    std::ofstream mn_file(filename_mn + ".txt");
+    std::ofstream pn_file(filename_pn + ".txt");
+    const std::string mn_errors_filename = filename + entropy_string + basis_functions->short_id() + "m_errors.txt";
+    const std::string pn_errors_filename = filename + "_" + basis_functions->short_id() + "p_errors.txt";
+    std::ofstream mn_errors_file(mn_errors_filename, std::ios_base::app);
+    std::ofstream pn_errors_file(pn_errors_filename, std::ios_base::app);
+    if (is_empty(mn_errors_filename))
+      mn_errors_file << "n l1error l2error linferror time(s) r" << std::endl;
+    if (is_empty(pn_errors_filename))
+      pn_errors_file << "n l1error l2error linferror time(s)" << std::endl;
+    for (size_t dd = 0; dd < dimDomain; ++dd) {
+      mn_file << "v" << dd << " ";
+      pn_file << "v" << dd << " ";
+    }
+    mn_file << "psi" << std::endl;
+    pn_file << "psi" << std::endl;
+    RangeFieldType l1norm(0), l2norm(0), linfnorm(0);
+    RangeFieldType l1error_mn(0), l2error_mn(0), linferror_mn(0);
+    RangeFieldType l1error_pn(0), l2error_pn(0), linferror_pn(0);
+    DynamicRangeType pn_coeffs(dimRange);
+    const auto pn_begin = std::chrono::steady_clock::now();
+    SolverHelper<>::solve(*basis_functions, u, pn_coeffs);
+    const auto pn_end = std::chrono::steady_clock::now();
+    const std::chrono::duration<double> pn_time = pn_end - pn_begin;
+    std::cout << "Pn solve took: " << pn_time.count() << " s!" << std::endl;
+    const auto quadrature = XT::Data::merged_quadrature(visualization_quadratures);
+    begin = std::chrono::steady_clock::now();
+    for (auto it = quadrature.begin(); it != quadrature.end(); ++it) {
+      const auto& quad_point = *it;
+      const auto v = quad_point.position();
+      const auto weight = quad_point.weight();
+      const auto basis = basis_functions->evaluate(v, it.first_index());
+      const auto psi_mn_prod = std::inner_product(basis.begin(), basis.end(), alpha.begin(), 0.);
+      const auto psi_mn = (MomentBasisType::entropy == EntropyType::MaxwellBoltzmann)
+                              ? std::exp(psi_mn_prod)
+                              : std::exp(psi_mn_prod) / (1 - std::exp(psi_mn_prod));
+      const auto psi_pn = pn_coeffs * basis;
+      for (size_t dd = 0; dd < dimDomain; ++dd) {
+        mn_file << XT::Common::to_string(v[dd], 15) << " ";
+        pn_file << XT::Common::to_string(v[dd], 15) << " ";
+      }
+      mn_file << XT::Common::to_string(psi_mn, 15) << std::endl;
+      pn_file << XT::Common::to_string(psi_pn, 15) << std::endl;
+      l1norm += std::abs(psi(v, basis_functions->is_negative(it))) * weight;
+      l2norm += std::pow(psi(v, basis_functions->is_negative(it)), 2) * weight;
+      linfnorm = std::max(std::abs(psi(v, basis_functions->is_negative(it))), linfnorm);
+      l1error_mn += std::abs(psi_mn - psi(v, basis_functions->is_negative(it))) * weight;
+      l2error_mn += std::pow(psi_mn - psi(v, basis_functions->is_negative(it)), 2) * weight;
+      linferror_mn = std::max(std::abs(psi_mn - psi(v, basis_functions->is_negative(it))), linferror_mn);
+      l1error_pn += std::abs(psi_pn - psi(v, basis_functions->is_negative(it))) * weight;
+      l2error_pn += std::pow(psi_pn - psi(v, basis_functions->is_negative(it)), 2) * weight;
+      linferror_pn = std::max(std::abs(psi_pn - psi(v, basis_functions->is_negative(it))), linferror_pn);
+    }
+    time = std::chrono::steady_clock::now() - begin;
+    std::cout << "Calculating errors took: " << time.count() << " s!" << std::endl;
+    mn_errors_file << dimRange << " " << XT::Common::to_string(l1error_mn, 15) << " "
+                   << XT::Common::to_string(l2error_mn, 15) << " " << XT::Common::to_string(linferror_mn, 15) << " "
+                   << mn_time.count() << " " << mn_ret->second.second << std::endl;
+    pn_errors_file << dimRange << " " << XT::Common::to_string(l1error_pn, 15) << " "
+                   << XT::Common::to_string(l2error_pn, 15) << " " << XT::Common::to_string(linferror_pn, 15) << " "
+                   << pn_time.count() << std::endl;
+    std::cout << basis_functions->mn_name() << " done!" << std::endl;
+  }
+};
+
+template <class MomentBasisType, class DiscreteFunctionType>
+const size_t MomentApproximation<MomentBasisType, DiscreteFunctionType>::dimDomain;
+template <class MomentBasisType, class DiscreteFunctionType>
+const size_t MomentApproximation<MomentBasisType, DiscreteFunctionType>::dimRange;
+
+} // namespace GDT
+} // namespace Dune
+
+#endif // DUNE_GDT_TEST_HYPERBOLIC_MOMENT_APPROXIMATION_HH
diff --git a/dune/gdt/momentmodels/triangulation.hh b/dune/gdt/test/momentmodels/triangulation.hh
similarity index 100%
rename from dune/gdt/momentmodels/triangulation.hh
rename to dune/gdt/test/momentmodels/triangulation.hh
diff --git a/dune/gdt/type_traits.hh b/dune/gdt/type_traits.hh
index 220064eaf..cb8e7abf3 100644
--- a/dune/gdt/type_traits.hh
+++ b/dune/gdt/type_traits.hh
@@ -80,7 +80,7 @@ class LocalFiniteElementFamilyInterface;
 template <class GV, size_t r, size_t rC, class R>
 class SpaceInterface;
 
-// from #include <dune/gdt/momentmodels/basisfunctions.hh>
+// from #include <dune/gdt/test/momentmodels/basisfunctions.hh>
 enum class EntropyType;
 
 template <class DomainFieldType,
@@ -173,7 +173,7 @@ struct is_space<S, true> : public std::is_base_of<SpaceInterface<typename S::GV,
 {};
 
 
-// from #include <dune/gdt/momentmodels/basisfunctions.hh>
+// from #include <dune/gdt/test/momentmodels/basisfunctions.hh>
 template <class T>
 struct is_hatfunction_basis : public std::false_type
 {};
-- 
GitLab