<!-- Important: This file has been automatically generated by generate_example_docs.py. Do not edit this file directly! -->


| [:arrow_left: Back to the main documentation](../README.md) | [:arrow_right: Continue with part 2](main.md) |
|---|---:|

# Part 1: Implementation of the shallow water flow simulation setup

The shallow water flow setup, including the bottom friction,
is implemented in the files `properties.hh`,
`problem.hh` and `spatialparams.hh`. In the first of these files, a new
type tag is declared for this problem. This allows the specialization
of DuMu<sup>x</sup> `properties` for this type tag, which can be used to customize compile-time
settings for the simulation. Two exemplary `properties`, that are mandatory to be
specialized, are `Problem` and `SpatialParams`. With the first, one sets the
`Problem` class to be used, in which users can define initial and boundary conditions.
Similarly, in the `SpatialParams` class one implements the parameter distributions
(e.g. friction value) that should be used by the model.

The documentation provided in the sequel is structured as follows:

[[_TOC_]]



## Compile-time settings (`properties.hh`)

In this file, the type tag used for the shallow water flow simulation is defined,
for which we then specialize `properties` to the needs of the desired setup.


<details open>
<summary><b>Click to hide/show the file documentation</b> (or inspect the [source code](../properties.hh))</summary>


### Includes
<details><summary> Click to show include files</summary>

The `ShallowWater` type tag specializes most of the `properties` required for a
shallow water flow simulation in DuMu<sup>x</sup>. We will use this in the following to inherit the
respective properties and subsequently specialize those `properties` for our
type tag, which we want to modify or for which no meaningful default can be set.

```cpp
#include <dumux/freeflow/shallowwater/model.hh>
```

We want to use `YaspGrid`, an implementation of the dune grid interface for structured grids:

```cpp
#include <dune/grid/yaspgrid.hh>
```

In this example, we want to discretize the equations with the cell centered finite volume
scheme using two-point-flux approximation:

```cpp
#include <dumux/discretization/cctpfa.hh>
```

We include the problem and spatial parameters headers used for this simulation.

```cpp
#include "problem.hh"
#include "spatialparams.hh"
```

</details>

### Type tag definition

First, a so-called type tag is created. Properties are traits specialized for this type tag (a simple `struct`).
The properties of two other type tags are inherited by adding the alias `InheritsFrom`.
Here, properties from the shallow water model (`TTag::ShallowWater`) and the
cell-centered finite volume scheme with two-point-flux approximation (`TTag::CCTpfaModel`)
are inherited. These other type tag definitions can be found in the included
headers `dumux/freeflow/shallowwater/model.hh` and `dumux/discretization/cctpfa.hh`.

```cpp
// We enter the namespace Dumux::Properties in order to import the entire Dumux namespace for general use:
namespace Dumux::Properties {

namespace TTag {
struct RoughChannel { using InheritsFrom = std::tuple<ShallowWater, CCTpfaModel>; };
}
```

### Property specializations

We use a structured Cartesian grid with tensor product structure.
`Dune::YaspGrid` (Yet Another Structure Parallel Grid) is defined in `dune/grid/yaspgrid.hh`
in the Dune module `dune-grid`.

```cpp
template<class TypeTag>
struct Grid<TypeTag, TTag::RoughChannel>
{ using type = Dune::YaspGrid<2, Dune::TensorProductCoordinates<GetPropType<TypeTag, Properties::Scalar>, 2> >; };
```

Next, we specialize the properties `Problem` and `SpatialParams` for our new type tag and
set the type to our problem and spatial parameter classes implemented
in `problem.hh` and `spatialparams.hh`.

```cpp
template<class TypeTag>
struct Problem<TypeTag, TTag::RoughChannel>
{ using type = Dumux::RoughChannelProblem<TypeTag>; };

template<class TypeTag>
struct SpatialParams<TypeTag, TTag::RoughChannel>
{
    using GridGeometry = GetPropType<TypeTag, Properties::GridGeometry>;
    using Scalar = GetPropType<TypeTag, Properties::Scalar>;
    using ElementVolumeVariables = typename GetPropType<TypeTag, Properties::GridVolumeVariables>::LocalView;
    using VolumeVariables = typename ElementVolumeVariables::VolumeVariables;

    using type = RoughChannelSpatialParams<GridGeometry, Scalar, VolumeVariables>;
};
```

Finally, we enable caching for the grid geometry. The cache
stores values that were already calculated for later usage.
This makes the simulation run faster but it uses more memory.

```cpp
template<class TypeTag>
struct EnableGridGeometryCache<TypeTag, TTag::RoughChannel>
{ static constexpr bool value = true; };

} // end namespace Dumux::Properties
```


</details>



## The problem file (`problem.hh`)

This file contains the __problem class__ which defines the initial and boundary
conditions for the shallow water flow simulation with bottom friction.
In addition, the analytical solution is defined here.


<details open>
<summary><b>Click to hide/show the file documentation</b> (or inspect the [source code](../problem.hh))</summary>


### Include files

The first include we need here is the `ShallowWaterProblem` class, the base
class from which we will derive.

```cpp
#include <dumux/freeflow/shallowwater/problem.hh>
```

In addition, we need the boundaryflux header, which handels the flux over
the model boundaries.

```cpp
#include <dumux/freeflow/shallowwater/boundaryfluxes.hh>
```

Include the `BoundaryTypes` class which specifies the boundary types set in this problem.

```cpp
#include <dumux/common/boundarytypes.hh>
```

### The problem class
We enter the problem class where all necessary boundary conditions and initial conditions are set for our simulation.
In addition the analytical solution of the problem is calculated.
As this is a shallow water problem, we inherit from the basic ShallowWaterProblem.

```cpp
namespace Dumux {

template <class TypeTag>
class RoughChannelProblem : public ShallowWaterProblem<TypeTag>
{
    // A few convenience aliases used throughout this class.
    using ParentType = ShallowWaterProblem<TypeTag>;
    using PrimaryVariables = GetPropType<TypeTag, Properties::PrimaryVariables>;
    using BoundaryTypes = Dumux::BoundaryTypes<PrimaryVariables::size()>;
    using Scalar = GetPropType<TypeTag, Properties::Scalar>;
    using Indices = typename GetPropType<TypeTag, Properties::ModelTraits>::Indices;
    using GridGeometry = GetPropType<TypeTag, Properties::GridGeometry>;
    using NeumannFluxes = GetPropType<TypeTag, Properties::NumEqVector>;
    using ElementVolumeVariables = typename GetPropType<TypeTag, Properties::GridVolumeVariables>::LocalView;
    using GridVariables = GetPropType<TypeTag, Properties::GridVariables>;
    using ElementFluxVariablesCache = typename GridVariables::GridFluxVariablesCache::LocalView;
    using FVElementGeometry = typename GetPropType<TypeTag, Properties::GridGeometry>::LocalView;
    using SubControlVolumeFace = typename FVElementGeometry::SubControlVolumeFace;
    using GridView = typename GetPropType<TypeTag, Properties::GridGeometry>::GridView;
    using Element = typename GridView::template Codim<0>::Entity;
    using GlobalPosition = typename Element::Geometry::GlobalCoordinate;
    using NumEqVector = GetPropType<TypeTag, Properties::NumEqVector>;
    using SubControlVolume = typename FVElementGeometry::SubControlVolume;

public:
    // This is the constructor of our problem class.
    RoughChannelProblem(std::shared_ptr<const GridGeometry> gridGeometry)
    : ParentType(gridGeometry)
    {
        // We read the parameters from the params.input file.
        constManningN_ = getParam<Scalar>("Problem.ManningN");
        bedSlope_ = getParam<Scalar>("Problem.BedSlope");
        discharge_ = getParam<Scalar>("Problem.Discharge");
        // We calculate the outflow boundary condition using the Gauckler-Manning-Strickler formula.
        hBoundary_ = this->gaucklerManningStrickler(discharge_,constManningN_,bedSlope_);
        // We initialize the analytic solution to a verctor of the appropriate size filled with zeros.
        exactWaterDepth_.resize(gridGeometry->numDofs(), 0.0);
        exactVelocityX_.resize(gridGeometry->numDofs(), 0.0);
    }
```

#### Analytical Solution

The analytical solution is calculated using the equation of Gauckler, Manning and Strickler.

```cpp

    // Equation of Gauckler, Manning and Strickler
    Scalar gaucklerManningStrickler(Scalar discharge, Scalar manningN, Scalar bedSlope)
    {
        using std::pow;
        using std::abs;
        using std::sqrt;

        return pow(abs(discharge)*manningN/sqrt(bedSlope), 0.6);
    }

    // Calculate the analytical solution
    void analyticalSolution()
    {
        using std::abs;

        for (const auto& element : elements(this->gridGeometry().gridView()))
        {
            const Scalar h = this->gaucklerManningStrickler(discharge_,constManningN_,bedSlope_);
            const Scalar u = abs(discharge_)/h;

            const auto eIdx = this->gridGeometry().elementMapper().index(element);
            exactWaterDepth_[eIdx] = h;
            exactVelocityX_[eIdx] = u;
        }
    }

    // Getter function for the analytical solution of the water depth
    const std::vector<Scalar>& getExactWaterDepth()
    {
        return exactWaterDepth_;
    }

    // Getter function for the analytical solution of the velocity in x-direction
    const std::vector<Scalar>& getExactVelocityX()
    {
        return exactVelocityX_;
    }
```

#### Bottom friction

The bottom friction is a source term and therefore handled by the `source` function.

```cpp
    NumEqVector source(const Element& element,
                       const FVElementGeometry& fvGeometry,
                       const ElementVolumeVariables& elemVolVars,
                       const SubControlVolume &scv) const
    {

        NumEqVector source (0.0);

        // Since the bed slope source term is handels within the flux computation,
        // in this model the bottom friction is the only source term.
        source += bottomFrictionSource(element, fvGeometry, elemVolVars, scv);

        return source;
    }
```

The calculation of the source term due to bottom friction needs the bottom shear stess.
This is the force per area, which works between the flow and the channel bed
(1D vector with two entries) and is calculated within the `FrictionLaw` class.
The bottom friction causes a loss of momentum. Thus the first entry of the `bottomFrictionSource`,
which is related to the mass balance equation is zero.
The second entry of the `bottomFricitonSource` corresponds to the momentum equation in x-direction
and is therefore equal to the first, the x-component, of the `bottomShearStress`.
Accordingly, the third entry of the `bottomFrictionSource` is equal to the second component of the `bottomShearStress`.

```cpp
    NumEqVector bottomFrictionSource(const Element& element,
                                      const FVElementGeometry& fvGeometry,
                                      const ElementVolumeVariables& elemVolVars,
                                      const SubControlVolume &scv) const
    {
        NumEqVector bottomFrictionSource(0.0);
        const auto& volVars = elemVolVars[scv];

        // bottom shear stress vector
        Dune::FieldVector<Scalar, 2> bottomShearStress = this->spatialParams().frictionLaw(element, scv).shearStress(volVars);

        // source term due to bottom friction
        bottomFrictionSource[0] = 0.0;
        bottomFrictionSource[1] = bottomShearStress[0];
        bottomFrictionSource[2] = bottomShearStress[1];

        return bottomFrictionSource;
    }
```

#### Boundary conditions

We define the __type of all boundary conditions__ as neumann-type,
because we use a weak imposition.

```cpp
    BoundaryTypes boundaryTypesAtPos(const GlobalPosition &globalPos) const
    {
        BoundaryTypes bcTypes;
        bcTypes.setAllNeumann();
        return bcTypes;
    }
```

In the following function we implement the __Neumann boundary conditions__.
Due to the weak imposition we calculate the flux at the boundary with a Riemann solver.
This needs the state of a virtual cell outside of the boundary (`boundaryStateVariables`),
wich is calculated with the Riemann invariants
(see: Yoon and Kang, "Finite Volume Model for Two-Dimensional Shallow Water Flows on Unstructured Grids").

```cpp
    NeumannFluxes neumann(const Element& element,
                          const FVElementGeometry& fvGeometry,
                          const ElementVolumeVariables& elemVolVars,
                          const ElementFluxVariablesCache& elemFluxVarsCache,
                          const SubControlVolumeFace& scvf) const
    {
        NeumannFluxes values(0.0);

        const auto& insideScv = fvGeometry.scv(scvf.insideScvIdx());
        const auto& insideVolVars = elemVolVars[insideScv];
        const auto& nxy = scvf.unitOuterNormal();
        const auto gravity = this->spatialParams().gravity(scvf.center());
        std::array<Scalar, 3> boundaryStateVariables;

        // Calculate the Riemann invariants for imposed discharge at the left side.
        if (scvf.center()[0] < this->gridGeometry().bBoxMin()[0] + eps_)
        {
            boundaryStateVariables = ShallowWater::fixedDischargeBoundary(discharge_,
                                                                          insideVolVars.waterDepth(),
                                                                          insideVolVars.velocity(0),
                                                                          insideVolVars.velocity(1),
                                                                          gravity,
                                                                          nxy);
        }
        // Calculate the Riemann invariants for imposed water depth at the right side.
        else if (scvf.center()[0] > this->gridGeometry().bBoxMax()[0] - eps_)
        {
            boundaryStateVariables =  ShallowWater::fixedWaterDepthBoundary(hBoundary_,
                                                                            insideVolVars.waterDepth(),
                                                                            insideVolVars.velocity(0),
                                                                            insideVolVars.velocity(1),
                                                                            gravity,
                                                                            nxy);
        }
        // Calculate the Riemann invariants for the no-flow boundary.
        else
        {
            boundaryStateVariables[0] = insideVolVars.waterDepth();
            boundaryStateVariables[1] = -insideVolVars.velocity(0);
            boundaryStateVariables[2] = -insideVolVars.velocity(1);
        }
        // Calculate the boundary fluxes based on a Riemann problem.
        auto riemannFlux = ShallowWater::riemannProblem(insideVolVars.waterDepth(),
                                                        boundaryStateVariables[0],
                                                        insideVolVars.velocity(0),
                                                        boundaryStateVariables[1],
                                                        insideVolVars.velocity(1),
                                                        boundaryStateVariables[2],
                                                        insideVolVars.bedSurface(),
                                                        insideVolVars.bedSurface(),
                                                        gravity,
                                                        nxy);

        values[Indices::massBalanceIdx] = riemannFlux[0];
        values[Indices::velocityXIdx]   = riemannFlux[1];
        values[Indices::velocityYIdx]   = riemannFlux[2];

        return values;
    }
```

#### Initial conditions

We specify the initial conditions for the primary variables (water depth, velocity in y-direction
and velocity in x-direction). In this example constant initial conditions are used. Therefore the
argument `globalPos` is not needed. If you want to impose spatial variable initial conditions,
you have to use the `globalPos` argument.

```cpp
    PrimaryVariables initialAtPos(const GlobalPosition &globalPos) const
    {
        PrimaryVariables initialValues(0.0);
        // We set the initial water depth to one meter.
        initialValues[0] = 1.0;
        // We set the x-component of the initial velocity to zero.
        initialValues[1] = 0.0;
        // We set the y-component of the initial velocity to zero.
        initialValues[2] = 0.0;

        return initialValues;
    }
```

We declare the private variables of the problem.

```cpp
private:
    // variables for the analytic solution.
    std::vector<Scalar> exactWaterDepth_;
    std::vector<Scalar> exactVelocityX_;
    // constant friction value (an analytic solution is only available for const friction).
    Scalar constManningN_;
    // The constant channel bed slope.
    Scalar bedSlope_;
    // The water depth at the outflow boundary.
    Scalar hBoundary_;
    // The discharge at the inflow boundary.
    Scalar discharge_;
    // We assign a private global variable for the epsilon:
    static constexpr Scalar eps_ = 1.0e-6;

}; // end class definition RoughChannelProblem
} // end namespace Dumux
```


</details>



## Parameter distributions (`spatialparams.hh`)

This file contains the __spatial parameters class__ which defines the
the friction law, including it's friction parameter, the acceleration
due to gravity and the altitude of the channel bed surface. In this example only the bed
surface has a non constant distribution.


<details open>
<summary><b>Click to hide/show the file documentation</b> (or inspect the [source code](../spatialparams.hh))</summary>


### Include files
We include the basic spatial parameters file for finite volumes, from which we will inherit.

```cpp
#include <dumux/material/spatialparams/fv.hh>
```

We include all friction laws.

```cpp
#include <dumux/material/fluidmatrixinteractions/frictionlaws/frictionlaw.hh>
#include <dumux/material/fluidmatrixinteractions/frictionlaws/manning.hh>
#include <dumux/material/fluidmatrixinteractions/frictionlaws/nikuradse.hh>
#include <dumux/material/fluidmatrixinteractions/frictionlaws/nofriction.hh>
```

### The spatial parameters class

In the `RoughChannelSpatialParams` class, we define all functions needed to describe
the rough channel for the shallow water problem.
We inherit from the `FVSpatialParams` class, which is the base class
for spatial parameters in the context of
applications using finite volume discretization schemes.

```cpp
namespace Dumux {

template<class GridGeometry, class Scalar, class VolumeVariables>
class RoughChannelSpatialParams
: public FVSpatialParams<GridGeometry, Scalar,
                         RoughChannelSpatialParams<GridGeometry, Scalar, VolumeVariables>>
{
    // This convenience aliases will be used throughout this class
    using ThisType = RoughChannelSpatialParams<GridGeometry, Scalar, VolumeVariables>;
    using ParentType = FVSpatialParams<GridGeometry, Scalar, ThisType>;
    using GridView = typename GridGeometry::GridView;
    using FVElementGeometry = typename GridGeometry::LocalView;
    using SubControlVolume = typename FVElementGeometry::SubControlVolume;
    using Element = typename GridView::template Codim<0>::Entity;
    using GlobalPosition = typename Element::Geometry::GlobalCoordinate;
```

In the following, the properties of the the rough channel are set. Namely, these are
the friction law, including it's friction parameter, the acceleration
due to gravity and the altitude of the channel bed surface.

```cpp
public:
    // In the constructor we read some values from the `params.input` and initialize the friciton law.
    RoughChannelSpatialParams(std::shared_ptr<const GridGeometry> gridGeometry)
    : ParentType(gridGeometry)
    {
        gravity_ = getParam<Scalar>("Problem.Gravity");
        bedSlope_ = getParam<Scalar>("Problem.BedSlope");
        frictionLawType_ = getParam<std::string>("Problem.FrictionLaw");
        initFrictionLaw();
    }

    // This function handles the initialization of the friction law based on the settings
    // specified in `params.input`.
    void initFrictionLaw()
    {
      if (frictionLawType_ == "Manning")
      {
          Scalar manningN = getParam<Scalar>("Problem.ManningN");
          frictionLaw_ = std::make_unique<FrictionLawManning<VolumeVariables>>(gravity_, manningN);
      }
      else if (frictionLawType_ == "Nikuradse")
      {
          Scalar ks = getParam<Scalar>("Problem.Ks");
          frictionLaw_ = std::make_unique<FrictionLawNikuradse<VolumeVariables>>(ks);
      }
      else if (frictionLawType_ == "None")
      {
          frictionLaw_ = std::make_unique<FrictionLawNoFriction<VolumeVariables>>();
      }
      else
      {
          std::cout<<"The FrictionLaw in params.input is unknown. Valid entries are `Manning`,"
                     " `Nikuradse` and `None`!"<<std::endl;
      }
    }

    // This function returns an object of the friction law class, already initialized with a friction value.
    const FrictionLaw<VolumeVariables>& frictionLaw(const Element& element,
                                                    const SubControlVolume& scv) const
    {
        return *frictionLaw_;
    }

    // This function returns the acceleration due to gravity.
    Scalar gravity(const GlobalPosition& globalPos) const
    {
        return gravity_;
    }

    // Define the bed surface based on the bed slope and the bed level at the inflow (10 m).
    Scalar bedSurface(const Element& element,
                      const SubControlVolume& scv) const
    {
        return 10.0 - element.geometry().center()[0] * bedSlope_;
    }

// We declare the private variables of the problem.
private:
    Scalar gravity_;
    Scalar bedSlope_;
    std::string frictionLawType_;
    std::unique_ptr<FrictionLaw<VolumeVariables>> frictionLaw_;
}; // end class definition of RoughChannelSpatialParams
} // end of namespace Dumux.
```


</details>


| [:arrow_left: Back to the main documentation](../README.md) | [:arrow_right: Continue with part 2](main.md) |
|---|---:|

