From 28070fe6ad63b9b5cfc5f22424a0f906e2c342e7 Mon Sep 17 00:00:00 2001
From: Felix Schindler <felix.schindler@wwu.de>
Date: Wed, 8 Aug 2018 00:24:04 +0200
Subject: [PATCH] [test.inviscid-compressible-flow] add another 1d euler test
 case

---
 dune/gdt/test/instationary-eocstudies/base.hh |   2 +-
 ...mpressible_flow__euler_1d__explicit__fv.cc | 165 +++++++++++++++---
 2 files changed, 146 insertions(+), 21 deletions(-)

diff --git a/dune/gdt/test/instationary-eocstudies/base.hh b/dune/gdt/test/instationary-eocstudies/base.hh
index 3f2911fef..28136a53f 100644
--- a/dune/gdt/test/instationary-eocstudies/base.hh
+++ b/dune/gdt/test/instationary-eocstudies/base.hh
@@ -299,7 +299,7 @@ protected:
     return time_points;
   }
 
-  const double T_end_;
+  double T_end_;
   const size_t num_refinements_;
   const size_t num_additional_refinements_for_reference_;
   const std::function<void(const DiscreteBochnerFunction<V, GV, m>&, const std::string&)> visualize_;
diff --git a/dune/gdt/test/inviscid-compressible-flow/inviscid_compressible_flow__euler_1d__explicit__fv.cc b/dune/gdt/test/inviscid-compressible-flow/inviscid_compressible_flow__euler_1d__explicit__fv.cc
index 9b013da8e..b597786e1 100644
--- a/dune/gdt/test/inviscid-compressible-flow/inviscid_compressible_flow__euler_1d__explicit__fv.cc
+++ b/dune/gdt/test/inviscid-compressible-flow/inviscid_compressible_flow__euler_1d__explicit__fv.cc
@@ -16,6 +16,8 @@
 #include <dune/xt/grid/grids.hh>
 #include <dune/xt/grid/walker.hh>
 #include <dune/xt/functions/base/sliced.hh>
+#include <dune/xt/functions/interfaces/element-functions.hh>
+#include <dune/xt/functions/lambda/function.hh>
 
 #include <dune/gdt/local/integrands/identity.hh>
 #include <dune/gdt/test/instationary-eocstudies/hyperbolic-fv.hh>
@@ -40,6 +42,7 @@ protected:
   using BaseType::m;
   using typename BaseType::E;
   using typename BaseType::F;
+  using typename BaseType::R;
   using typename BaseType::DF;
   using typename BaseType::GV;
   using typename BaseType::GP;
@@ -78,7 +81,7 @@ public:
 
   std::vector<std::string> quantities() const override final
   {
-    return {"rel mass conserv   error"};
+    return {"rel mass conserv   error"}; // <- This is on purpose, see column header formatting in ConvergenceStudy.
   }
 
   virtual std::map<std::string, std::map<std::string, double>>
@@ -124,8 +127,35 @@ protected:
 
   DF make_initial_values(const S& space) override final
   {
-    return Problem::access().template make_initial_values<V>(space);
-  }
+    if (boundary_treatment == "inflow_from_the_left_by_heuristic_euler_treatment_impermeable_wall_right") {
+      const auto& euler_tools = Problem::access().euler_tools;
+      return interpolate<V>(0,
+                            [&](const auto& /*xx*/, const auto& /*param*/) {
+                              FieldVector<R, m> primitive_variables(0.);
+                              // density
+                              primitive_variables[0] = 0.5;
+                              // velocity
+                              for (size_t ii = 0; ii < d; ++ii)
+                                primitive_variables[1 + ii] = 0.;
+                              // pressure
+                              primitive_variables[m - 1] = 0.4;
+                              return euler_tools.to_conservative(primitive_variables);
+                            },
+                            space);
+    } else
+      return Problem::access().template make_initial_values<V>(space);
+  } // ... make_initial_values(...)
+
+  double estimate_dt(const S& space) override final
+  {
+    if (boundary_treatment == "inflow_from_the_left_by_heuristic_euler_treatment_impermeable_wall_right")
+      return estimate_dt_for_hyperbolic_system(space.grid_view(),
+                                               make_initial_values(space),
+                                               flux(),
+                                               /*boundary_data_range=*/{{0.5, 0., 0.4}, {1.5, 0.5, 0.4}});
+    else
+      return estimate_dt_for_hyperbolic_system(space.grid_view(), make_initial_values(space), flux());
+  } // ... estimate_dt(...)
 
   GP make_initial_grid() override final
   {
@@ -146,17 +176,18 @@ protected:
       boundary_info = std::make_unique<XT::Grid::NormalBasedBoundaryInfo<XT::Grid::extract_intersection_t<GV>>>();
       boundary_info->register_new_normal({-1}, new XT::Grid::ImpermeableBoundary());
       boundary_info->register_new_normal({1}, new XT::Grid::ImpermeableBoundary());
-      XT::Grid::ApplyOn::CustomBoundaryIntersections<GV> impermeable_wall_filter(*boundary_info,
-                                                                                 new XT::Grid::ImpermeableBoundary());
+      const XT::Grid::ApplyOn::CustomBoundaryIntersections<GV> impermeable_wall_filter(
+          *boundary_info, new XT::Grid::ImpermeableBoundary());
       auto op = std::make_unique<AdvectionFvOperator<GV, V, m>>(space.grid_view(),
                                                                 *self.numerical_flux_,
                                                                 space,
                                                                 space,
                                                                 /*periodicity_restriction=*/impermeable_wall_filter);
       // the actual handling of impermeable walls
-      op->append([&](const auto& u,
+      op->append(/*numerical_boundary_flux=*/[&](
+                     const auto& u,
                      const auto& n,
-                     const auto& /*param*/ = {}) { return euler_tools.flux_at_impermeable_walls(u, n); },
+                     const auto& /*param*/) { return euler_tools.flux_at_impermeable_walls(u, n); },
                  {},
                  impermeable_wall_filter);
       return op;
@@ -164,8 +195,8 @@ protected:
       boundary_info = std::make_unique<XT::Grid::NormalBasedBoundaryInfo<XT::Grid::extract_intersection_t<GV>>>();
       boundary_info->register_new_normal({-1}, new XT::Grid::ImpermeableBoundary());
       boundary_info->register_new_normal({1}, new XT::Grid::ImpermeableBoundary());
-      XT::Grid::ApplyOn::CustomBoundaryIntersections<GV> impermeable_wall_filter(*boundary_info,
-                                                                                 new XT::Grid::ImpermeableBoundary());
+      const XT::Grid::ApplyOn::CustomBoundaryIntersections<GV> impermeable_wall_filter(
+          *boundary_info, new XT::Grid::ImpermeableBoundary());
       auto op = std::make_unique<AdvectionFvOperator<GV, V, m>>(space.grid_view(),
                                                                 *self.numerical_flux_,
                                                                 space,
@@ -173,11 +204,104 @@ protected:
                                                                 /*periodicity_restriction=*/impermeable_wall_filter);
       // the actual handling of impermeable walls, see [DF2015, p. 415, (8.66 - 8.67)]
       op->append(
+          /*boundary_extrapolation=*/
           [&](const auto& intersection,
               const auto& xx_in_reference_intersection_coordinates,
-              const auto& /*f*/,
+              const auto& /*flux*/,
               const auto& u,
-              const auto& /*mu*/ = {}) {
+              const auto& /*param*/) {
+            const auto normal = intersection.unitOuterNormal(xx_in_reference_intersection_coordinates);
+            const auto rho = euler_tools.density_from_conservative(u);
+            auto velocity = euler_tools.velocity_from_conservative(u);
+            velocity -= normal * 2. * (velocity * normal);
+            const auto pressure = euler_tools.pressure_from_conservative(u);
+            return euler_tools.to_conservative(XT::Common::hstack(rho, velocity, pressure));
+          },
+          {},
+          impermeable_wall_filter);
+      return op;
+    } else if (boundary_treatment == "inflow_from_the_left_by_heuristic_euler_treatment_impermeable_wall_right") {
+      periodic_density_variation_ =
+          std::unique_ptr<XT::Functions::LambdaFunction<d, m>>(new XT::Functions::LambdaFunction<d, m>(
+              /*order=*/0,
+              [&](const auto& /*xx*/, const auto& param) {
+                FieldVector<R, m> primitive_variables(0.);
+                const auto t = param.get("_t").at(0);
+                // density
+                primitive_variables[0] = 1. + 0.5 * std::sin(2. * M_PI * (t - 0.25));
+                // velocity
+                for (size_t ii = 0; ii < d; ++ii)
+                  primitive_variables[1 + ii] = 0.25 + 0.25 * std::sin(2. * M_PI * (t - 0.25));
+                // pressure
+                primitive_variables[m - 1] = 0.4;
+                return euler_tools.to_conservative(primitive_variables);
+              },
+              /*name=*/"periodic_density_variation",
+              /*parameter_type=*/{"_t", 1}));
+      local_periodic_density_variation_ = periodic_density_variation_->template as_grid_function<E>().local_function();
+      // inflow/outflow left, impermeable wall right
+      boundary_info = std::make_unique<XT::Grid::NormalBasedBoundaryInfo<XT::Grid::extract_intersection_t<GV>>>();
+      boundary_info->register_new_normal({-1}, new XT::Grid::InflowOutflowBoundary());
+      boundary_info->register_new_normal({1}, new XT::Grid::ImpermeableBoundary());
+      const XT::Grid::ApplyOn::CustomBoundaryIntersections<GV> impermeable_wall_filter(
+          *boundary_info, new XT::Grid::ImpermeableBoundary());
+      const XT::Grid::ApplyOn::CustomBoundaryIntersections<GV> inflow_outflow_filter(
+          *boundary_info, new XT::Grid::InflowOutflowBoundary());
+      auto op = std::make_unique<AdvectionFvOperator<GV, V, m>>(
+          space.grid_view(),
+          *self.numerical_flux_,
+          space,
+          space,
+          /*periodicity_restriction=*/*(inflow_outflow_filter || impermeable_wall_filter));
+      // the actual handling of inflow/outflow, see [DF2015, p. 421, (8.88)]
+      // (supposedly this does not work well for slow flows!)
+      const auto heuristic_euler_inflow_outflow_treatment = [&](const auto& intersection,
+                                                                const auto& xx_in_reference_intersection_coordinates,
+                                                                const auto& /*flux*/,
+                                                                const auto& u,
+                                                                const auto& param) {
+        using RangeType = XT::Common::FieldVector<R, m>;
+        // evaluate boundary values
+        const auto element = intersection.inside();
+        const auto xx_in_reference_element_coordinates =
+            intersection.geometryInInside().global(xx_in_reference_intersection_coordinates);
+        local_periodic_density_variation_->bind(element);
+        const RangeType bv = local_periodic_density_variation_->evaluate(xx_in_reference_element_coordinates, param);
+        // determine flow regime
+        const auto a = euler_tools.speed_of_sound_from_conservative(u);
+        const auto velocity = euler_tools.velocity_from_conservative(u);
+        const auto normal = intersection.unitOuterNormal(xx_in_reference_intersection_coordinates);
+        const auto flow_speed = velocity * normal;
+        // compute v
+        if (flow_speed < -a) {
+          // supersonic inlet
+          return bv;
+        } else if (!(flow_speed > 0)) {
+          // subsonic inlet
+          const auto rho_outer = euler_tools.density_from_conservative(bv);
+          const auto v_outer = euler_tools.velocity_from_conservative(bv);
+          const auto p_inner = euler_tools.pressure_from_conservative(u);
+          return euler_tools.to_conservative(XT::Common::hstack(rho_outer, v_outer, p_inner));
+        } else if (flow_speed < a) {
+          // subsonic outlet
+          const auto rho_inner = euler_tools.density_from_conservative(u);
+          const auto v_inner = euler_tools.velocity_from_conservative(u);
+          const auto p_outer = euler_tools.pressure_from_conservative(bv);
+          return euler_tools.to_conservative(XT::Common::hstack(rho_inner, v_inner, p_outer));
+        } else {
+          // supersonic outlet
+          return RangeType(u);
+        }
+      }; // ... heuristic_euler_inflow_outflow_treatment(...)
+      op->append(heuristic_euler_inflow_outflow_treatment, {}, inflow_outflow_filter);
+      // the actual handling of impermeable walls, see above
+      op->append(
+          /*boundary_extrapolation=*/
+          [&](const auto& intersection,
+              const auto& xx_in_reference_intersection_coordinates,
+              const auto& /*flux*/,
+              const auto& u,
+              const auto& /*param*/) {
             const auto normal = intersection.unitOuterNormal(xx_in_reference_intersection_coordinates);
             const auto rho = euler_tools.density_from_conservative(u);
             auto velocity = euler_tools.velocity_from_conservative(u);
@@ -203,6 +327,8 @@ protected:
   size_t visualization_steps_;
   std::string boundary_treatment;
   std::unique_ptr<XT::Grid::NormalBasedBoundaryInfo<XT::Grid::extract_intersection_t<GV>>> boundary_info;
+  std::unique_ptr<XT::Functions::LambdaFunction<d, m>> periodic_density_variation_;
+  std::unique_ptr<typename XT::Functions::ElementFunctionInterface<E, m>> local_periodic_density_variation_;
 }; // class InviscidCompressibleFlowEulerExplicitFvTest
 
 
@@ -226,12 +352,11 @@ TEST_F(InviscidCompressibleFlow1dEulerExplicitFvTest, impermeable_walls_by_invis
   this->boundary_treatment = "impermeable_walls_by_inviscid_mirror_treatment";
   this->run();
 }
-
-
-#if 0
-// TEST_F(InviscidCompressibleFlowEuler1dExplicitFV,
-//       inflow_from_the_left_by_heuristic_euler_treatment_impermeable_wall_right)
-//{
-//  this->inflow_from_the_left_by_heuristic_euler_treatment_impermeable_wall_right(10*100);
-//}
-#endif // 0
+TEST_F(InviscidCompressibleFlow1dEulerExplicitFvTest,
+       inflow_from_the_left_by_heuristic_euler_treatment_impermeable_wall_right)
+{
+  this->T_end_ = 2; // We need more time to hit the right wall
+  this->set_numerical_flux("vijayasundaram");
+  this->boundary_treatment = "inflow_from_the_left_by_heuristic_euler_treatment_impermeable_wall_right";
+  this->run();
+}
-- 
GitLab