From b2f929202cc3302f7026cf041fe0ebcc133f0d7a Mon Sep 17 00:00:00 2001
From: Tobias Leibner <tobias.leibner@googlemail.com>
Date: Fri, 20 Dec 2019 17:33:13 +0100
Subject: [PATCH] [local.operators.advection-fv] add dynamic evaluate

---
 dune/gdt/local/operators/advection-fv.hh      | 124 ++++++++++++------
 .../test/inviscid-compressible-flow/base.hh   |  19 +--
 .../entropic-coords-mn-discretization.hh      |  22 ++--
 dune/gdt/test/momentmodels/entropyflux.hh     |  17 ++-
 .../momentmodels/entropyflux_kineticcoords.hh |  69 +++++++---
 .../test/momentmodels/mn-discretization.hh    |  15 ++-
 .../test/momentmodels/pn-discretization.hh    |  14 +-
 7 files changed, 183 insertions(+), 97 deletions(-)

diff --git a/dune/gdt/local/operators/advection-fv.hh b/dune/gdt/local/operators/advection-fv.hh
index 51ff9b74b..fdebe9549 100644
--- a/dune/gdt/local/operators/advection-fv.hh
+++ b/dune/gdt/local/operators/advection-fv.hh
@@ -60,7 +60,7 @@ public:
   using typename BaseType::LocalSourceType;
   using typename BaseType::SourceSpaceType;
   using typename BaseType::SourceType;
-  using StateType = typename XT::Functions::RangeTypeSelector<SR, m, 1>::type;
+  using DynamicStateType = typename XT::Functions::RangeTypeSelector<SR, m, 1>::dynamic_type;
   using NumericalFluxType = NumericalFluxInterface<I, d, m, RR>;
   using LocalIntersectionCoords = typename NumericalFluxType::LocalIntersectionCoords;
   static const typename LocalSourceType::DomainType static_x;
@@ -71,6 +71,9 @@ public:
     : BaseType(2, numerical_flux.parameter_type())
     , numerical_flux_(numerical_flux.copy())
     , source_is_elementwise_constant_(source_is_elementwise_constant)
+    , u_(m)
+    , v_(m)
+    , g_(m)
   {}
 
   LocalAdvectionFvCouplingOperator(const SourceType& source,
@@ -79,6 +82,9 @@ public:
     : BaseType(source, 2, numerical_flux.parameter_type())
     , numerical_flux_(numerical_flux.copy())
     , source_is_elementwise_constant_(source_is_elementwise_constant)
+    , u_(m)
+    , v_(m)
+    , g_(m)
   {}
 
   LocalAdvectionFvCouplingOperator(const SourceSpaceType& source_space,
@@ -88,6 +94,9 @@ public:
     : BaseType(source_space, source_vector, 2, numerical_flux.parameter_type())
     , numerical_flux_(numerical_flux.copy())
     , source_is_elementwise_constant_(source_is_elementwise_constant)
+    , u_(m)
+    , v_(m)
+    , g_(m)
   {}
 
   LocalAdvectionFvCouplingOperator(const DiscreteSourceType& source, const NumericalFluxType& numerical_flux)
@@ -98,6 +107,9 @@ public:
     : BaseType(other)
     , numerical_flux_(other.numerical_flux_->copy())
     , source_is_elementwise_constant_(other.source_is_elementwise_constant_)
+    , u_(m)
+    , v_(m)
+    , g_(m)
   {}
 
   std::unique_ptr<BaseType> copy() const override final
@@ -120,20 +132,23 @@ public:
                       || (local_range_outside.space().type() != SpaceType::finite_volume),
                   Exceptions::operator_error,
                   "Use LocalAdvectionDgCouplingOperator instead!");
-    u_ = local_sources_[0]->evaluate(source_is_elementwise_constant_ ? static_x
-                                                                     : intersection().geometryInInside().center());
-    v_ = local_sources_[1]->evaluate(source_is_elementwise_constant_ ? static_x
-                                                                     : intersection().geometryInOutside().center());
+    local_sources_[0]->evaluate(
+        source_is_elementwise_constant_ ? static_x : intersection().geometryInInside().center(), u_, param);
+    local_sources_[1]->evaluate(
+        source_is_elementwise_constant_ ? static_x : intersection().geometryInOutside().center(), v_, param);
     const auto normal = intersection().centerUnitOuterNormal();
     if (numerical_flux_->x_dependent())
       x_in_intersection_coords_ = intersection().geometry().local(intersection().geometry().center());
-    const auto g = numerical_flux_->apply(x_in_intersection_coords_, u_, v_, normal, param);
+    numerical_flux_->apply(x_in_intersection_coords_, u_, v_, normal, g_, param);
     const auto h_intersection = intersection().geometry().volume();
-    const auto h_inside_element = intersection().inside().geometry().volume();
-    const auto h_outside_element = intersection().outside().geometry().volume();
+    const auto hinv_inside_element = 1. / intersection().inside().geometry().volume();
+    const auto hinv_outside_element = 1. / intersection().outside().geometry().volume();
+    auto& local_range_inside_dofs = local_range_inside.dofs();
+    auto& local_range_outside_dofs = local_range_outside.dofs();
     for (size_t ii = 0; ii < m; ++ii) {
-      local_range_inside.dofs()[ii] += (g[ii] * h_intersection) / h_inside_element;
-      local_range_outside.dofs()[ii] -= (g[ii] * h_intersection) / h_outside_element;
+      const auto g_ii = g_[ii] * h_intersection;
+      local_range_inside_dofs[ii] += g_ii * hinv_inside_element;
+      local_range_outside_dofs[ii] -= g_ii * hinv_outside_element;
     }
   } // ... apply(...)
 
@@ -149,8 +164,9 @@ private:
   std::unique_ptr<NumericalFluxType> numerical_flux_;
   const bool source_is_elementwise_constant_;
   mutable LocalIntersectionCoords x_in_intersection_coords_;
-  mutable StateType u_;
-  mutable StateType v_;
+  mutable DynamicStateType u_;
+  mutable DynamicStateType v_;
+  mutable DynamicStateType g_;
 }; // class LocalAdvectionFvCouplingOperator
 
 template <class I,
@@ -186,9 +202,11 @@ public:
   using typename BaseType::SourceType;
 
   using StateDomainType = FieldVector<typename SGV::ctype, SGV::dimension>;
-  using StateType = typename CouplingOperatorType::StateType;
-  using LambdaType = std::function<StateType(
-      const StateType& /*u*/, const StateDomainType& /*n*/, const XT::Common::Parameter& /*param*/)>;
+  using DynamicStateType = typename CouplingOperatorType::DynamicStateType;
+  using LambdaType = std::function<void(const DynamicStateType& /*u*/,
+                                        const StateDomainType& /*n*/,
+                                        DynamicStateType& /*g*/,
+                                        const XT::Common::Parameter& /*param*/)>;
 
   // When using this constructor, source has to be set by a call to with_source before calling apply
   LocalAdvectionFvBoundaryTreatmentByCustomNumericalFluxOperator(
@@ -198,6 +216,8 @@ public:
     : BaseType(1, boundary_treatment_param_type)
     , numerical_boundary_flux_(numerical_boundary_flux_lambda)
     , source_is_elementwise_constant_(source_is_elementwise_constant)
+    , u_(m)
+    , g_(m)
   {}
 
   LocalAdvectionFvBoundaryTreatmentByCustomNumericalFluxOperator(
@@ -208,6 +228,8 @@ public:
     : BaseType(source, 1, boundary_treatment_param_type)
     , numerical_boundary_flux_(numerical_boundary_flux_lambda)
     , source_is_elementwise_constant_(source_is_elementwise_constant)
+    , u_(m)
+    , g_(m)
   {}
 
   LocalAdvectionFvBoundaryTreatmentByCustomNumericalFluxOperator(
@@ -219,6 +241,8 @@ public:
     : BaseType(source_space, source_vector, 1, boundary_treatment_param_type)
     , numerical_boundary_flux_(numerical_boundary_flux_lambda)
     , source_is_elementwise_constant_(source_is_elementwise_constant)
+    , u_(m)
+    , g_(m)
   {}
 
   LocalAdvectionFvBoundaryTreatmentByCustomNumericalFluxOperator(
@@ -235,6 +259,8 @@ public:
     : BaseType(other)
     , numerical_boundary_flux_(other.numerical_boundary_flux_)
     , source_is_elementwise_constant_(other.source_is_elementwise_constant_)
+    , u_(m)
+    , g_(m)
   {}
 
   std::unique_ptr<BaseType> copy() const override final
@@ -257,21 +283,23 @@ public:
     DUNE_THROW_IF(local_range_inside.space().type() != SpaceType::finite_volume,
                   Exceptions::operator_error,
                   "Use LocalAdvectionDgBoundaryTreatmentByCustomNumericalFluxOperator instead!");
-    u_ = local_sources_[0]->evaluate(source_is_elementwise_constant_ ? CouplingOperatorType::static_x
-                                                                     : intersection().geometryInInside().center());
+    local_sources_[0]->evaluate(source_is_elementwise_constant_ ? CouplingOperatorType::static_x
+                                                                : intersection().geometryInInside().center(),
+                                u_);
     const auto normal = intersection().centerUnitOuterNormal();
-    const auto g = numerical_boundary_flux_(u_, normal, param);
-    const auto h_intersection = intersection().geometry().volume();
-    const auto h_element = intersection().inside().geometry().volume();
+    numerical_boundary_flux_(u_, normal, g_, param);
+    auto& local_range_inside_dofs = local_range_inside.dofs();
+    const auto factor = intersection().geometry().volume() / intersection().inside().geometry().volume();
     for (size_t ii = 0; ii < m; ++ii)
-      local_range_inside.dofs()[ii] += (g[ii] * h_intersection) / h_element;
+      local_range_inside_dofs[ii] += g_[ii] * factor;
   } // ... apply(...)
 
 private:
   using BaseType::local_sources_;
   const LambdaType numerical_boundary_flux_;
   const bool source_is_elementwise_constant_;
-  mutable StateType u_;
+  mutable DynamicStateType u_;
+  mutable DynamicStateType g_;
 }; // class LocalAdvectionFvBoundaryTreatmentByCustomNumericalFluxOperator
 
 
@@ -296,12 +324,13 @@ public:
   using NumericalFluxType = NumericalFluxInterface<I, d, m, RF>;
   using LocalIntersectionCoords = typename NumericalFluxType::LocalIntersectionCoords;
   using FluxType = typename NumericalFluxType::FluxType;
-  using StateType = typename CouplingOperatorType::StateType;
-  using LambdaType = std::function<StateType(const IntersectionType& /*intersection*/,
-                                             const FieldVector<D, d - 1>& /*xx_in_reference_intersection_coordinates*/,
-                                             const FluxType& /*flux*/,
-                                             const StateType& /*u*/,
-                                             const XT::Common::Parameter& /*param*/)>;
+  using DynamicStateType = typename CouplingOperatorType::DynamicStateType;
+  using LambdaType = std::function<void(const IntersectionType& /*intersection*/,
+                                        const FieldVector<D, d - 1>& /*xx_in_reference_intersection_coordinates*/,
+                                        const FluxType& /*flux*/,
+                                        const DynamicStateType& /*u*/,
+                                        DynamicStateType& /*v*/,
+                                        const XT::Common::Parameter& /*param*/)>;
 
   // When using this constructor, source has to be set by a call to with_source before calling apply
   LocalAdvectionFvBoundaryTreatmentByCustomExtrapolationOperator(
@@ -313,6 +342,9 @@ public:
     , numerical_flux_(numerical_flux.copy())
     , extrapolate_(boundary_extrapolation_lambda)
     , source_is_elementwise_constant_(source_is_elementwise_constant)
+    , u_(m)
+    , v_(m)
+    , g_(m)
   {}
 
   LocalAdvectionFvBoundaryTreatmentByCustomExtrapolationOperator(
@@ -325,6 +357,9 @@ public:
     , numerical_flux_(numerical_flux.copy())
     , extrapolate_(boundary_extrapolation_lambda)
     , source_is_elementwise_constant_(source_is_elementwise_constant)
+    , u_(m)
+    , v_(m)
+    , g_(m)
   {}
 
   LocalAdvectionFvBoundaryTreatmentByCustomExtrapolationOperator(
@@ -357,6 +392,9 @@ public:
     , numerical_flux_(other.numerical_flux_->copy())
     , extrapolate_(other.extrapolate_)
     , source_is_elementwise_constant_(other.source_is_elementwise_constant_)
+    , u_(m)
+    , v_(m)
+    , g_(m)
   {}
 
   std::unique_ptr<BaseType> copy() const override final
@@ -380,19 +418,22 @@ public:
                   "Use LocalAdvectionDgBoundaryTreatmentByCustomExtrapolationOperator instead!");
     if (numerical_flux_->x_dependent())
       x_in_intersection_coords_ = intersection().geometry().local(intersection().geometry().center());
-    u_ = local_sources_[0]->evaluate(source_is_elementwise_constant_ ? CouplingOperatorType::static_x
-                                                                     : intersection().geometryInInside().center());
-    v_ = extrapolate_(intersection(),
-                      ReferenceElements<D, d - 1>::general(intersection().type()).position(0, 0),
-                      numerical_flux_->flux(),
-                      u_,
-                      param);
+    local_sources_[0]->evaluate(source_is_elementwise_constant_ ? CouplingOperatorType::static_x
+                                                                : intersection().geometryInInside().center(),
+                                u_,
+                                param);
+    extrapolate_(intersection(),
+                 ReferenceElements<D, d - 1>::general(intersection().type()).position(0, 0),
+                 numerical_flux_->flux(),
+                 u_,
+                 v_,
+                 param);
     const auto normal = intersection().centerUnitOuterNormal();
-    const auto g = numerical_flux_->apply(x_in_intersection_coords_, u_, v_, normal, param);
-    const auto h_intersection = intersection().geometry().volume();
-    const auto h_element = intersection().inside().geometry().volume();
+    numerical_flux_->apply(x_in_intersection_coords_, u_, v_, normal, g_, param);
+    auto& local_range_inside_dofs = local_range_inside.dofs();
+    const auto factor = intersection().geometry().volume() / intersection().inside().geometry().volume();
     for (size_t ii = 0; ii < m; ++ii)
-      local_range_inside.dofs()[ii] += (g[ii] * h_intersection) / h_element;
+      local_range_inside_dofs[ii] += g_[ii] * factor;
   } // ... apply(...)
 
 protected:
@@ -408,8 +449,9 @@ private:
   const LambdaType extrapolate_;
   const bool source_is_elementwise_constant_;
   mutable LocalIntersectionCoords x_in_intersection_coords_;
-  mutable StateType u_;
-  mutable StateType v_;
+  mutable DynamicStateType u_;
+  mutable DynamicStateType v_;
+  mutable DynamicStateType g_;
 }; // class LocalAdvectionFvBoundaryTreatmentByCustomExtrapolationOperator
 
 
diff --git a/dune/gdt/test/inviscid-compressible-flow/base.hh b/dune/gdt/test/inviscid-compressible-flow/base.hh
index 2f8a45915..31f63ade3 100644
--- a/dune/gdt/test/inviscid-compressible-flow/base.hh
+++ b/dune/gdt/test/inviscid-compressible-flow/base.hh
@@ -195,8 +195,8 @@ protected:
                                                                 /*periodicity_restriction=*/impermeable_wall_filter);
       // the actual handling of impermeable walls
       op->append(/*numerical_boundary_flux=*/
-                 [&](const auto& u, const auto& n, const auto& /*param*/) {
-                   return euler_tools.flux_at_impermeable_walls(XT::LA::convert_to<RangeType>(u), n);
+                 [&](const auto& u, const auto& n, auto& ret, const auto& /*param*/) {
+                   ret = euler_tools.flux_at_impermeable_walls(XT::LA::convert_to<RangeType>(u), n);
                  },
                  {},
                  impermeable_wall_filter);
@@ -219,6 +219,7 @@ protected:
               const auto& xx_in_reference_intersection_coordinates,
               const auto& /*flux*/,
               const auto& u,
+              auto& v,
               const auto& /*param*/) {
             const auto normal = intersection.unitOuterNormal(xx_in_reference_intersection_coordinates);
             const auto rho_v_p = euler_tools.primitives(XT::LA::convert_to<RangeType>(u));
@@ -226,7 +227,7 @@ protected:
             auto velocity = std::get<1>(rho_v_p);
             const auto& pressure = std::get<2>(rho_v_p);
             velocity -= normal * 2. * (velocity * normal);
-            return euler_tools.conservative(rho, velocity, pressure);
+            v = euler_tools.conservative(rho, velocity, pressure);
           },
           {},
           impermeable_wall_filter);
@@ -264,6 +265,7 @@ protected:
                                                                 const auto& xx_in_reference_intersection_coordinates,
                                                                 const auto& /*flux*/,
                                                                 const auto& u_,
+                                                                auto& v,
                                                                 const auto& param) {
         // evaluate boundary values
         const auto element = intersection.inside();
@@ -280,22 +282,22 @@ protected:
         // compute v
         if (flow_speed < -a) {
           // supersonic inlet
-          return bv;
+          v = bv;
         } else if (!(flow_speed > 0)) {
           // subsonic inlet
           const auto rho_outer = euler_tools.density(bv);
           const auto v_outer = euler_tools.velocity(bv);
           const auto p_inner = euler_tools.pressure(u);
-          return euler_tools.conservative(rho_outer, v_outer, p_inner);
+          v = euler_tools.conservative(rho_outer, v_outer, p_inner);
         } else if (flow_speed < a) {
           // subsonic outlet
           const auto rho_inner = euler_tools.density(u);
           const auto v_inner = euler_tools.velocity(u);
           const auto p_outer = euler_tools.pressure(bv);
-          return euler_tools.conservative(rho_inner, v_inner, p_outer);
+          v = euler_tools.conservative(rho_inner, v_inner, p_outer);
         } else {
           // supersonic outlet
-          return RangeType(u);
+          v = u;
         }
       }; // ... heuristic_euler_inflow_outflow_treatment(...)
       op->append(heuristic_euler_inflow_outflow_treatment, {}, inflow_outflow_filter);
@@ -306,6 +308,7 @@ protected:
               const auto& xx_in_reference_intersection_coordinates,
               const auto& /*flux*/,
               const auto& u,
+              auto& v,
               const auto& /*param*/) {
             const auto normal = intersection.unitOuterNormal(xx_in_reference_intersection_coordinates);
             const auto rho_v_p = euler_tools.primitives(XT::LA::convert_to<RangeType>(u));
@@ -313,7 +316,7 @@ protected:
             auto velocity = std::get<1>(rho_v_p);
             const auto& pressure = std::get<2>(rho_v_p);
             velocity -= normal * 2. * (velocity * normal);
-            return euler_tools.conservative(rho, velocity, pressure);
+            v = euler_tools.conservative(rho, velocity, pressure);
           },
           {},
           impermeable_wall_filter);
diff --git a/dune/gdt/test/momentmodels/entropic-coords-mn-discretization.hh b/dune/gdt/test/momentmodels/entropic-coords-mn-discretization.hh
index cbf2cff91..e547c7619 100644
--- a/dune/gdt/test/momentmodels/entropic-coords-mn-discretization.hh
+++ b/dune/gdt/test/momentmodels/entropic-coords-mn-discretization.hh
@@ -79,6 +79,7 @@ struct HyperbolicEntropicCoordsMnDiscretization
     using GenericFunctionType = XT::Functions::GenericFunction<dimDomain, dimRange, 1, RangeFieldType>;
     using DomainType = FieldVector<RangeFieldType, dimDomain>;
     using RangeType = FieldVector<RangeFieldType, dimRange>;
+    using DynamicRangeType = DynamicVector<RangeFieldType>;
     //        static const RangeFieldType scale_factor = 1e2;
 
     //******************* create grid and FV space ***************************************
@@ -124,7 +125,9 @@ struct HyperbolicEntropicCoordsMnDiscretization
           alpha_boundary_vals.insert(std::make_pair(x, analytical_flux->get_alpha(u)));
         }
     GenericFunctionType boundary_values_alpha(
-        1, [&](const DomainType& x, const XT::Common::Parameter&) { return alpha_boundary_vals[x]; });
+        1, [&](const DomainType& x, DynamicRangeType& ret, const XT::Common::Parameter&) {
+          ret = alpha_boundary_vals[x];
+        });
 
 
     // ***************** project initial values to discrete function *********************
@@ -224,7 +227,6 @@ struct HyperbolicEntropicCoordsMnDiscretization
     using BoundaryOperator =
         LocalAdvectionFvBoundaryTreatmentByCustomExtrapolationOperator<I, VectorType, GV, dimRange>;
     using LambdaType = typename BoundaryOperator::LambdaType;
-    using StateType = typename BoundaryOperator::StateType;
 
     // calculate boundary kinetic fluxes
     // apply density_operator first to store boundary_evaluations
@@ -233,27 +235,29 @@ struct HyperbolicEntropicCoordsMnDiscretization
     density_operator.apply(alpha.dofs().vector(), alpha.dofs().vector());
 
     // store boundary fluxes
-    std::map<DomainType, RangeType, XT::Common::FieldVectorFloatLess> boundary_fluxes;
+    std::map<DomainType, DynamicRangeType, XT::Common::FieldVectorFloatLess> boundary_fluxes;
     for (const auto& element : Dune::elements(grid_view))
       for (const auto& intersection : Dune::intersections(grid_view, element))
         if (intersection.boundary()) {
           const auto x = intersection.geometry().center();
           const auto dd = intersection.indexInInside() / 2;
-          const auto boundary_flux = problem.kinetic_boundary_flux(x, intersection.centerUnitOuterNormal()[dd], dd);
+          const DynamicRangeType boundary_flux =
+              problem.kinetic_boundary_flux(x, intersection.centerUnitOuterNormal()[dd], dd);
           boundary_fluxes.insert(std::make_pair(x, boundary_flux));
         }
     GenericFunctionType boundary_kinetic_fluxes(
-        1, [&](const DomainType& x, const XT::Common::Parameter&) { return boundary_fluxes[x]; });
+        1, [&](const DomainType& x, DynamicRangeType& ret, const XT::Common::Parameter&) { ret = boundary_fluxes[x]; });
 
 
     LambdaType boundary_lambda =
         [&](const I& intersection,
             const FieldVector<RangeFieldType, dimDomain - 1>& xx_in_reference_intersection_coordinates,
             const AnalyticalFluxType& /*flux*/,
-            const StateType& /*u*/,
-            const XT::Common::Parameter& /*param*/) {
-          return boundary_kinetic_fluxes.evaluate(
-              intersection.geometry().global(xx_in_reference_intersection_coordinates));
+            const DynamicRangeType& /*u*/,
+            DynamicRangeType& v,
+            const XT::Common::Parameter& param) {
+          boundary_kinetic_fluxes.evaluate(
+              intersection.geometry().global(xx_in_reference_intersection_coordinates), v, param);
         };
     XT::Grid::ApplyOn::NonPeriodicBoundaryIntersections<GV> filter;
     advection_operator.append(boundary_lambda, {}, filter);
diff --git a/dune/gdt/test/momentmodels/entropyflux.hh b/dune/gdt/test/momentmodels/entropyflux.hh
index e10a013de..bbd3e6f7e 100644
--- a/dune/gdt/test/momentmodels/entropyflux.hh
+++ b/dune/gdt/test/momentmodels/entropyflux.hh
@@ -313,12 +313,14 @@ public:
         index_set_, entity_caches_, use_thread_cache_, use_entity_cache_, mutexes_, *implementation_);
   }
 
-  StateType evaluate_kinetic_flux(const E& inside_entity,
-                                  const E& outside_entity,
-                                  const StateType& u_i,
-                                  const StateType& u_j,
-                                  const DomainType& n_ij,
-                                  const size_t dd) const
+  template <class StateTp, class RetType>
+  void evaluate_kinetic_flux(const E& inside_entity,
+                             const E& outside_entity,
+                             const StateTp& u_i,
+                             const StateTp& u_j,
+                             const DomainType& n_ij,
+                             const size_t dd,
+                             RetType& ret) const
   {
     // calculate \sum_{i=1}^d < \omega_i m G_\alpha(u) > n_i
     const auto local_func = derived_local_function();
@@ -326,9 +328,10 @@ public:
     const auto alpha_i = local_func->get_alpha(u_i, true)->first;
     local_func->bind(outside_entity);
     const auto alpha_j = local_func->get_alpha(u_j, true)->first;
-    return implementation_->evaluate_kinetic_flux_with_alphas(alpha_i, alpha_j, n_ij, dd);
+    ret = implementation_->evaluate_kinetic_flux_with_alphas(alpha_i, alpha_j, n_ij, dd);
   } // StateType evaluate_kinetic_flux(...)
 
+
   // Returns alpha(u), starting from alpha_iso. To get better performance when calculating several alphas, use
   // Localfunction's get_alpha
   std::unique_ptr<AlphaReturnType> get_alpha(const StateType& u, const bool regularize) const
diff --git a/dune/gdt/test/momentmodels/entropyflux_kineticcoords.hh b/dune/gdt/test/momentmodels/entropyflux_kineticcoords.hh
index a4ecb753c..8d1b1462c 100644
--- a/dune/gdt/test/momentmodels/entropyflux_kineticcoords.hh
+++ b/dune/gdt/test/momentmodels/entropyflux_kineticcoords.hh
@@ -14,6 +14,7 @@
 #include <memory>
 
 #include <dune/xt/common/float_cmp.hh>
+#include <dune/xt/common/numeric.hh>
 #include <dune/xt/common/vector_less.hh>
 
 #include <dune/xt/functions/interfaces/flux-function.hh>
@@ -48,6 +49,7 @@ public:
   static const size_t dimFlux = MomentBasis::dimFlux;
   static const size_t basis_dimRange = MomentBasis::dimRange;
   using typename BaseType::DomainType;
+  using typename BaseType::DynamicStateType;
   using typename BaseType::E;
   using typename BaseType::LocalFunctionType;
   using typename BaseType::RangeFieldType;
@@ -119,6 +121,8 @@ public:
     const ImplementationType& implementation_;
   }; // class Localfunction
 
+  using RangeReturnType = typename Localfunction::RangeReturnType;
+
   bool x_dependent() const override final
   {
     return false;
@@ -134,14 +138,18 @@ public:
     return std::make_unique<Localfunction>(*implementation_);
   }
 
-  StateType evaluate_kinetic_flux(const E& /*inside_entity*/,
-                                  const E& /*outside_entity*/,
-                                  const StateType& flux_i,
-                                  const StateType& flux_j,
-                                  const DomainType& n_ij,
-                                  const size_t dd) const
+  template <class StateTp, class RetType>
+  void evaluate_kinetic_flux(const E& /*inside_entity*/,
+                             const E& /*outside_entity*/,
+                             const StateTp& flux_i,
+                             const StateTp& flux_j,
+                             const DomainType& n_ij,
+                             const size_t dd,
+                             RetType& ret) const
   {
-    return (flux_i + flux_j) * n_ij[dd];
+    ret = flux_i;
+    ret += flux_j;
+    ret *= n_ij[dd];
   } // StateType evaluate_kinetic_flux(...)
 
   const MomentBasis& basis_functions() const
@@ -159,6 +167,11 @@ public:
     return implementation_->get_u((*eta_ast_prime_evaluations_)[entity_index]);
   }
 
+  void get_u(const size_t entity_index, StateType& u) const
+  {
+    implementation_->get_u((*eta_ast_prime_evaluations_)[entity_index], u);
+  }
+
   StateType get_alpha(const StateType& u) const
   {
     const auto alpha = implementation_->get_alpha(u)->first;
@@ -183,12 +196,25 @@ public:
         densities_stencil, precomputed_fluxes, dd);
   }
 
-  void apply_inverse_hessian(const size_t entity_index, const StateType& u, StateType& Hinv_u) const
+  void apply_kinetic_flux_with_kinetic_reconstruction(const RangeFieldType& h_inv,
+                                                      const QuadratureWeightsType& densities_left,
+                                                      const QuadratureWeightsType& densities_entity,
+                                                      const QuadratureWeightsType& densities_right,
+                                                      StateType* u_left,
+                                                      StateType* u_entity,
+                                                      StateType* u_right,
+                                                      const size_t dd) const
   {
-    implementation_->apply_inverse_hessian((*eta_ast_twoprime_evaluations_)[entity_index], u, Hinv_u);
+    implementation_->template apply_kinetic_flux_with_kinetic_reconstruction<slope>(
+        h_inv, densities_left, densities_entity, densities_right, u_left, u_entity, u_right, dd);
   }
 
-  void store_evaluations(const size_t entity_index, StateType& alpha, bool check = true)
+  void apply_inverse_hessian(const size_t entity_index, StateType& u) const
+  {
+    implementation_->apply_inverse_hessian((*eta_ast_twoprime_evaluations_)[entity_index], u);
+  }
+
+  void store_evaluations(const size_t entity_index, StateType& alpha, const RangeFieldType psi_min, bool check = true)
   {
     implementation_->store_exp_evaluations(exp_evaluations_[entity_index], alpha);
     if (entropy != EntropyType::MaxwellBoltzmann) {
@@ -199,15 +225,15 @@ public:
     set_eta_ast_pointers();
     // check for inf and nan and very low densities
     if (check) {
-      const auto& u = get_u(entity_index);
-      for (auto&& entry : u)
-        if (std::isnan(entry) || std::isinf(entry))
-          DUNE_THROW(Dune::MathError, "inf or nan in u!");
-      const auto rho = basis_functions().density(u);
-      if (rho < 1e-9) {
-        alpha = basis_functions().alpha_iso(1e-8);
-        store_evaluations(entity_index, alpha, false);
-      }
+      const auto u = get_u(entity_index);
+      const double* u_ptr = &(u[0]);
+      // if (std::any_of(u_ptr, u_ptr + basis_dimRange, [](const auto& a) { return std::isnan(a) || std::isinf(a); }))
+      const auto val = XT::Common::reduce(u_ptr, u_ptr + basis_dimRange, 0.);
+      if (std::isnan(val) || std::isinf(val))
+        DUNE_THROW(Dune::MathError, "inf or nan in u!");
+      const bool changed = basis_functions().adjust_alpha_to_ensure_min_density(alpha, psi_min);
+      if (changed)
+        store_evaluations(entity_index, alpha, psi_min, false);
     }
   }
 
@@ -297,6 +323,11 @@ public:
     return boundary_distribution_evaluations_;
   }
 
+  RangeReturnType evaluate_with_alpha(const StateType& alpha) const
+  {
+    return implementation_->evaluate_with_alpha(alpha);
+  }
+
 private:
   std::shared_ptr<ImplementationType> implementation_;
   std::vector<QuadratureWeightsType> exp_evaluations_;
diff --git a/dune/gdt/test/momentmodels/mn-discretization.hh b/dune/gdt/test/momentmodels/mn-discretization.hh
index 038cad0a2..6f8f9703e 100644
--- a/dune/gdt/test/momentmodels/mn-discretization.hh
+++ b/dune/gdt/test/momentmodels/mn-discretization.hh
@@ -148,14 +148,15 @@ struct HyperbolicMnDiscretization
     using BoundaryOperator =
         LocalAdvectionFvBoundaryTreatmentByCustomExtrapolationOperator<I, VectorType, GV, dimRange>;
     using LambdaType = typename BoundaryOperator::LambdaType;
-    using StateType = typename BoundaryOperator::StateType;
+    using DynamicStateType = typename BoundaryOperator::DynamicStateType;
     LambdaType boundary_lambda =
         [&boundary_values](const I& intersection,
                            const FieldVector<RangeFieldType, dimDomain - 1>& xx_in_reference_intersection_coordinates,
                            const AnalyticalFluxType& /*flux*/,
-                           const StateType& /*u*/,
-                           const XT::Common::Parameter& /*param*/) {
-          return boundary_values->evaluate(intersection.geometry().global(xx_in_reference_intersection_coordinates));
+                           const DynamicStateType& /*u*/,
+                           DynamicStateType& v,
+                           const XT::Common::Parameter& param) {
+          boundary_values->evaluate(intersection.geometry().global(xx_in_reference_intersection_coordinates), v, param);
         };
     XT::Grid::ApplyOn::NonPeriodicBoundaryIntersections<GV> filter;
     advection_operator.append(boundary_lambda, {}, filter);
@@ -243,13 +244,13 @@ struct HyperbolicMnTest
   void run(const double tol = TestCaseType::ExpectedResultsType::tol)
   {
     auto norms = HyperbolicMnDiscretization<TestCaseType>::run(
-                     1,
+                     DXTC_CONFIG.get("num_save_steps", 1),
                      0,
                      TestCaseType::quad_order,
                      TestCaseType::quad_refinements,
-                     "",
+                     DXTC_CONFIG.get("grid_size", ""),
                      2,
-                     TestCaseType::t_end,
+                     DXTC_CONFIG.get("t_end", TestCaseType::t_end),
                      "test",
                      Dune::GDT::is_full_moment_basis<typename TestCaseType::MomentBasis>::value)
                      .first;
diff --git a/dune/gdt/test/momentmodels/pn-discretization.hh b/dune/gdt/test/momentmodels/pn-discretization.hh
index cf2edc275..10c40bb69 100644
--- a/dune/gdt/test/momentmodels/pn-discretization.hh
+++ b/dune/gdt/test/momentmodels/pn-discretization.hh
@@ -206,8 +206,9 @@ struct HyperbolicPnDiscretization
     using BoundaryValueType = typename ProblemType::BoundaryValueType;
     static constexpr size_t dimDomain = MomentBasis::dimDomain;
     static constexpr size_t dimRange = MomentBasis::dimRange;
-    using MatrixType = typename XT::LA::Container<RangeFieldType>::MatrixType;
-    using VectorType = typename XT::LA::Container<RangeFieldType>::VectorType;
+    static const auto la_backend = TestCaseType::la_backend;
+    using MatrixType = typename XT::LA::Container<RangeFieldType, la_backend>::MatrixType;
+    using VectorType = typename XT::LA::Container<RangeFieldType, la_backend>::VectorType;
 
     //******************* create grid and FV space ***************************************
     auto grid_config = ProblemType::default_grid_cfg();
@@ -294,14 +295,15 @@ struct HyperbolicPnDiscretization
     using BoundaryOperator =
         LocalAdvectionFvBoundaryTreatmentByCustomExtrapolationOperator<I, VectorType, GV, dimRange>;
     using LambdaType = typename BoundaryOperator::LambdaType;
-    using StateType = typename BoundaryOperator::StateType;
+    using DynamicStateType = typename BoundaryOperator::DynamicStateType;
     LambdaType boundary_lambda =
         [&boundary_values](const I& intersection,
                            const FieldVector<RangeFieldType, dimDomain - 1>& xx_in_reference_intersection_coordinates,
                            const AnalyticalFluxType& /*flux*/,
-                           const StateType& /*u*/,
-                           const XT::Common::Parameter& /*param*/) {
-          return boundary_values->evaluate(intersection.geometry().global(xx_in_reference_intersection_coordinates));
+                           const DynamicStateType& /*u*/,
+                           DynamicStateType& v,
+                           const XT::Common::Parameter& param) {
+          boundary_values->evaluate(intersection.geometry().global(xx_in_reference_intersection_coordinates), v, param);
         };
     XT::Grid::ApplyOn::NonPeriodicBoundaryIntersections<GV> filter;
     advection_operator.append(boundary_lambda, {}, filter);
-- 
GitLab