From f563b6ae0f2c5d04a3decb859b74ed55d9605882 Mon Sep 17 00:00:00 2001
From: Martin Utz <martin.utz@baw.de>
Date: Thu, 13 Jun 2019 12:42:24 +0200
Subject: [PATCH] [swe][frictionlaws] Enable test for Nikuradse

One can run the test now also with Nikuradse. But be aware that the
friction value in the input file is a Manning values.
Addintional changes
- The names of the variables used for the calculation of the
  boundaryfluxes are changed, because they were not really clear. Also the
  documentation of their file is improved.
- Some smaller modification were also applyied, which were demanded
  by the discussion about the merge request.
---
 dumux/freeflow/shallowwater/boundaryfluxes.hh | 81 ++++++++++++-------
 .../frictionlaws/frictionlaw.hh               |  4 +-
 .../frictionlaws/manning.hh                   |  2 +-
 .../frictionlaws/nikuradse.hh                 |  6 +-
 .../shallowwater/roughchannel/params.input    |  2 +-
 .../shallowwater/roughchannel/problem.hh      | 18 +++--
 .../roughchannel/spatialparams.hh             |  3 +-
 7 files changed, 77 insertions(+), 39 deletions(-)

diff --git a/dumux/freeflow/shallowwater/boundaryfluxes.hh b/dumux/freeflow/shallowwater/boundaryfluxes.hh
index 178db2c80b..97833bf74f 100644
--- a/dumux/freeflow/shallowwater/boundaryfluxes.hh
+++ b/dumux/freeflow/shallowwater/boundaryfluxes.hh
@@ -19,8 +19,13 @@
 /*!
  * \file
  * \ingroup ShallowWaterModel
- * \brief Compute boundary conditions (cell state) via Riemann invariants
+ * \brief Compute boundary conditions for the Riemann Solver
  *
+ * The boundary conditions are given at the the outer face of the
+ * the boundary cells. In this form the boundary condition can't be
+ * processed by the riemann Solver, because it needs two cell states, one at
+ * each side of a face. Therefore they Riemann invariants are used to
+ * calculate a virtual outer state.
  */
 #ifndef DUMUX_SHALLOWWATER_BOUNDARYFLUXES_HH
 #define DUMUX_SHALLOWWATER_BOUNDARYFLUXES_HH
@@ -32,49 +37,69 @@ namespace Dumux {
 namespace ShallowWater {
 
 /*!
- * \brief compute the cell state for fixed water depth boundary.
+ * \brief Compute the outer cell state for fixed water depth boundary.
+ *
+ * \param waterDepthBoundary Discharge per meter at the boundary face [m^2/s]
+ * \param waterDepthInside Water depth in the inner cell [m]
+ * \param velocityXInside Velocity in x-direction in the inner cell [m/s]
+ * \param velocityYInside Velocity in y-direction in the inner cell [m/s]
+ * \param gravity Gravity constant [m^3/s]
+ * \param nxy Normal vector of the boundary face
+ *
+ * \return cellStateOutside The outer cell state
  */
 template<class Scalar, class GlobalPosition>
 std::array<Scalar, 3> fixedWaterDepthBoundary(const Scalar waterDepthBoundary,
-                                              const Scalar waterDepthLeft,
-                                              const Scalar velocityXLeft,
-                                              const Scalar velocityYLeft,
+                                              const Scalar waterDepthInside,
+                                              const Scalar velocityXInside,
+                                              const Scalar velocityYInside,
+                                              const Scalar gravity,
                                               const GlobalPosition& nxy)
 
 {
-    std::array<Scalar, 3> cellStateRight;
-    cellStateRight[0] = waterDepthBoundary;
+    std::array<Scalar, 3> cellStateOutside;
+    cellStateOutside[0] = waterDepthBoundary;
 
     using std::sqrt;
-    const auto uboundIn = nxy[0] * velocityXLeft  + nxy[1] * velocityYLeft;
-    const auto uboundQut =  uboundIn + 2.0 * sqrt(9.81 * waterDepthLeft) - 2.0 * sqrt(9.81 * cellStateRight[0]);
+    const auto uboundIn = nxy[0] * velocityXInside  + nxy[1] * velocityYInside;
+    const auto uboundQut =  uboundIn + 2.0 * sqrt(gravity * waterDepthInside) - 2.0 * sqrt(gravity * cellStateOutside[0]);
 
-    cellStateRight[1] = (nxy[0] * uboundQut); // we only use the normal part
-    cellStateRight[2] = (nxy[1] * uboundQut); // we only use the normal part
+    cellStateOutside[1] = (nxy[0] * uboundQut); // we only use the normal part
+    cellStateOutside[2] = (nxy[1] * uboundQut); // we only use the normal part
 
-    return cellStateRight;
+    return cellStateOutside;
 }
 
 /*!
- * \brief compute the cell state for a fixed discharge boundary.
+ * \brief Compute the outer cell state for a fixed discharge boundary.
+ *
+ * \param dischargeBoundary Discharge per meter at the boundary face [m^2/s]
+ * \param waterDepthInside Water depth in the inner cell [m]
+ * \param velocityXInside Velocity in x-direction in the inner cell [m/s]
+ * \param velocityYInside Velocity in y-direction in the inner cell [m/s]
+ * \param gravity Gravity constant [m^3/s]
+ * \param nxy Normal vector of the boundary face
+ *
+ * \return cellStateOutside The outer cell state
  */
 template<class Scalar, class GlobalPosition>
-std::array<Scalar, 3> fixedDischargeBoundary(const Scalar qlocal,
-                                             const Scalar waterDepthLeft,
-                                             const Scalar velocityXLeft,
-                                             const Scalar velocityYLeft,
+std::array<Scalar, 3> fixedDischargeBoundary(const Scalar dischargeBoundary,
+                                             const Scalar waterDepthInside,
+                                             const Scalar velocityXInside,
+                                             const Scalar velocityYInside,
+                                             const Scalar gravity,
                                              const GlobalPosition& nxy)
 {
-    std::array<Scalar, 3> cellStateRight;
+    std::array<Scalar, 3> cellStateOutside;
     using std::abs;
     using std::sqrt;
     using std::max;
 
     // only impose if abs(q) > 0
-    if (abs(qlocal) > 1.0e-9)
+    if (abs(dischargeBoundary) > 1.0e-9)
     {
-        const auto uboundIn = nxy[0]*velocityXLeft + nxy[1]*velocityYLeft;
-        const auto alphal = uboundIn + 2.0*sqrt(9.81 * waterDepthLeft);
+        const auto uboundIn = nxy[0]*velocityXInside + nxy[1]*velocityYInside;
+        const auto alphal = uboundIn + 2.0*sqrt(gravity * waterDepthInside);
 
         //initial guess for hstar solved with newton
         constexpr Scalar tol_hstar = 1.0E-12;
@@ -84,8 +109,8 @@ std::array<Scalar, 3> fixedDischargeBoundary(const Scalar qlocal,
         Scalar hstar = 0.1;
         for (int i = 0; i < maxstep_hstar; ++i)
         {
-            Scalar f_hstar = alphal - qlocal/hstar - 2 * sqrt(9.81 * hstar);
-            Scalar df_hstar = (f_hstar -(alphal - qlocal/(hstar + ink_hstar) - 2 * sqrt(9.81 * (hstar+ink_hstar))))/ink_hstar;
+            Scalar f_hstar = alphal - dischargeBoundary/hstar - 2 * sqrt(gravity * hstar);
+            Scalar df_hstar = (f_hstar -(alphal - dischargeBoundary/(hstar + ink_hstar) - 2 * sqrt(gravity * (hstar+ink_hstar))))/ink_hstar;
             Scalar dx_hstar = -f_hstar/df_hstar;
             hstar = max(hstar - dx_hstar,0.001);
 
@@ -93,13 +118,13 @@ std::array<Scalar, 3> fixedDischargeBoundary(const Scalar qlocal,
                 break;
         }
 
-        const auto qinner = (nxy[0] * waterDepthLeft * velocityYLeft) - (nxy[1] * waterDepthLeft * velocityXLeft);
-        cellStateRight[0] = hstar;
-        cellStateRight[1] = (nxy[0] * qlocal - nxy[1] * qinner)/hstar;
-        cellStateRight[2] = (nxy[1] * qlocal + nxy[0] * qinner)/hstar;
+        const auto qinner = (nxy[0] * waterDepthInside * velocityYInside) - (nxy[1] * waterDepthInside * velocityXInside);
+        cellStateOutside[0] = hstar;
+        cellStateOutside[1] = (nxy[0] * dischargeBoundary - nxy[1] * qinner)/hstar;
+        cellStateOutside[2] = (nxy[1] * dischargeBoundary + nxy[0] * qinner)/hstar;
     }
 
-    return cellStateRight;
+    return cellStateOutside;
 }
 
 } // end namespace ShallowWater
diff --git a/dumux/material/fluidmatrixinteractions/frictionlaws/frictionlaw.hh b/dumux/material/fluidmatrixinteractions/frictionlaws/frictionlaw.hh
index c66da30da8..fb57e2af46 100644
--- a/dumux/material/fluidmatrixinteractions/frictionlaws/frictionlaw.hh
+++ b/dumux/material/fluidmatrixinteractions/frictionlaws/frictionlaw.hh
@@ -45,7 +45,7 @@ public:
      * \return ustar_h friction used for the source term in shallow water models.
      */
 
-    const virtual Scalar computeUstarH(const Scalar waterDept, const Scalar frictionValue) = 0;
+    virtual Scalar computeUstarH(const Scalar waterDept, const Scalar frictionValue) const = 0;
 
     /*!
      * \brief Limit the friction for small water depth.
@@ -76,7 +76,7 @@ public:
      * \param roughnessHeight roughness height of the representive structure (e.g. largest grain size).
      * \param waterDepth water depth.
      */
-    Scalar limitRoughH(const Scalar roughnessHeight, const Scalar waterDepth)
+    Scalar limitRoughH(const Scalar roughnessHeight, const Scalar waterDepth) const
     {
         using std::min;
         using std::max;
diff --git a/dumux/material/fluidmatrixinteractions/frictionlaws/manning.hh b/dumux/material/fluidmatrixinteractions/frictionlaws/manning.hh
index 53062431cf..db06d92b83 100644
--- a/dumux/material/fluidmatrixinteractions/frictionlaws/manning.hh
+++ b/dumux/material/fluidmatrixinteractions/frictionlaws/manning.hh
@@ -50,7 +50,7 @@ public:
      *
      * \return ustar_h friction used for the source term in shallow water models.
      */
-    const Scalar computeUstarH(const Scalar waterDepth, const Scalar frictionValue) final
+    Scalar computeUstarH(const Scalar waterDepth, const Scalar frictionValue) const final
     {
         using std::pow;
 
diff --git a/dumux/material/fluidmatrixinteractions/frictionlaws/nikuradse.hh b/dumux/material/fluidmatrixinteractions/frictionlaws/nikuradse.hh
index 87767d975a..ec3a9d91b3 100644
--- a/dumux/material/fluidmatrixinteractions/frictionlaws/nikuradse.hh
+++ b/dumux/material/fluidmatrixinteractions/frictionlaws/nikuradse.hh
@@ -40,6 +40,8 @@ template <typename Scalar>
 class FrictionLawNikuradse : public FrictionLaw<Scalar>
 {
 public:
+    FrictionLawNikuradse(const Scalar gravity)
+        : gravity_(gravity) {}
     /*!
      * \brief Compute the friction ustar_h.
      *
@@ -49,7 +51,7 @@ public:
      * \return ustar_h friction used for the source term in shallow water models.
      */
 
-    const Scalar computeUstarH(const Scalar waterDepth, const Scalar frictionValue) final
+    Scalar computeUstarH(const Scalar waterDepth, const Scalar frictionValue) const final
     {
         using std::pow;
         using std::log;
@@ -61,6 +63,8 @@ public:
         ustar_h = pow(0.41,2.0)/pow(log((12*(waterDepth + rough_h))/frictionValue),2.0);
         return ustar_h;
     }
+private:
+    Scalar gravity_;
 };
 
 } // end namespace Dumux
diff --git a/test/freeflow/shallowwater/roughchannel/params.input b/test/freeflow/shallowwater/roughchannel/params.input
index 1afacd7100..3ab64984f0 100644
--- a/test/freeflow/shallowwater/roughchannel/params.input
+++ b/test/freeflow/shallowwater/roughchannel/params.input
@@ -3,7 +3,7 @@ Name = roughchannel
 FrictionValue = 0.025 # [-]
 BedSlope = 0.001 # [-]
 Gravity = 9.81 # [m/s^2]
-Discharge = -1.0 # [m/s] discharge at the inflow boundary
+Discharge = -1.0 # [m^2/s] discharge per meter at the inflow boundary
 FrictionLaw = Manning
 
 [TimeLoop]
diff --git a/test/freeflow/shallowwater/roughchannel/problem.hh b/test/freeflow/shallowwater/roughchannel/problem.hh
index 4198c27290..501e0ee6d7 100644
--- a/test/freeflow/shallowwater/roughchannel/problem.hh
+++ b/test/freeflow/shallowwater/roughchannel/problem.hh
@@ -144,15 +144,21 @@ public:
         discharge_ = getParam<Scalar>("Problem.Discharge");
         hBoundary_ = this->gauklerManningStrickler(discharge_,constManningN_,bedSlope_);
 
+        const auto gravity = this->spatialParams().gravity();
         if (getParam<std::string>("Problem.FrictionLaw") == ("Manning"))
         {
-            const auto gravity = this->spatialParams().gravity();
-            auto ptrManning = std::make_shared<FrictionLawManning<Scalar>>(gravity);
-            frictionLaw_ = std::static_pointer_cast<FrictionLaw<Scalar>>(ptrManning);
+            frictionLaw_ = std::make_shared<FrictionLawManning<Scalar>>(gravity);
+        }
+        else if (getParam<std::string>("Problem.FrictionLaw") == ("Nikuradse"))
+        {
+            frictionLaw_ = std::make_shared<FrictionLawNikuradse<Scalar>>(gravity);
+            std::cout<<"\nWARNING: This test is meant to be run for the friction law after Manning.\n";
+            std::cout<<"         You are running it with Nikuradse, although the friction values in\n";
+            std::cout<<"         the input file and the analytic solution don't fit to Nikuradse!\n\n.";
         }
         else
         {
-            std::cout<<"Change the FrictionLaw in params.input. This test is only valid for Manning!";
+            std::cout<<"The FrictionLaw in params.input is unknown. Valid entries are 'Manning' and 'Nikuradse'!";
         }
     }
 
@@ -175,7 +181,7 @@ public:
         using std::abs;
         using std::sqrt;
 
-        return std::pow(std::abs(discharge)*manningN/sqrt(bedSlope), 0.6);
+        return pow(abs(discharge)*manningN/sqrt(bedSlope), 0.6);
     }
 
     //! Udpate the analytical solution
@@ -306,6 +312,7 @@ public:
                                                                           insideVolVars.waterDepth(),
                                                                           insideVolVars.velocity(0),
                                                                           insideVolVars.velocity(1),
+                                                                          gravity,
                                                                           nxy);
         }
         // impose water depth at the right side
@@ -315,6 +322,7 @@ public:
                                                                             insideVolVars.waterDepth(),
                                                                             insideVolVars.velocity(0),
                                                                             insideVolVars.velocity(1),
+                                                                            gravity,
                                                                             nxy);
         }
         // no flow boundary
diff --git a/test/freeflow/shallowwater/roughchannel/spatialparams.hh b/test/freeflow/shallowwater/roughchannel/spatialparams.hh
index 888d168765..e7b6d17f46 100644
--- a/test/freeflow/shallowwater/roughchannel/spatialparams.hh
+++ b/test/freeflow/shallowwater/roughchannel/spatialparams.hh
@@ -96,7 +96,8 @@ public:
     *
     * \param element The current element
     * \param scv The sub-control volume inside the element.
-    * \return the bed surface
+    *
+    * \return The bed surface
     */
     Scalar bedSurface(const Element& element,
                       const SubControlVolume& scv) const
-- 
GitLab