<!-- 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](postprocessing.md) |
|---|---:|

# Part 1: Implementation

The implementation of simulation setup and main flow is structured as follows:

[[_TOC_]]


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

In this file, the type tag used for this simulation is defined,
for which we then specialize properties (compile time options) 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 includes</summary>

The `NavierStokes` type tag specializes most of the properties required for Navier-
Stokes single-phase flow simulations in DuMuX. 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/navierstokes/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 staggered-grid
scheme which is so far the only available option for free-flow models in DuMux:

```cpp
#include <dumux/discretization/staggered/freeflow/properties.hh>
```

The fluid properties are specified in the following headers (we use a liquid with constant properties as the fluid phase):

```cpp
#include <dumux/material/components/constant.hh>
#include <dumux/material/fluidsystems/1pliquid.hh>
```

We include the problem header used for this simulation.

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

</details>

### Type tag definition

We define a type tag for our simulation with the name `LidDrivenCavityExample`
and inherit the properties specialized for the type tags `NavierStokes` and `StaggeredFreeFlowModel`.

```cpp

namespace Dumux::Properties {

// We define the `LidDrivenCavityExample` type tag and let it inherit from the single-phase `NavierStokes`
// tag (model) and the `StaggeredFreeFlowModel` (discretization scheme).
namespace TTag {
struct LidDrivenCavityExample { using InheritsFrom = std::tuple<NavierStokes, StaggeredFreeFlowModel>; };
} // end namespace TTag
```

### Property specializations

In the following piece of code, mandatory properties for which no meaningful
default exist are specialized for our type tag `LidDrivenCavityExample`.

```cpp
// This sets the fluid system to be used. Here, we use a liquid with constant properties as fluid phase.
template<class TypeTag>
struct FluidSystem<TypeTag, TTag::LidDrivenCavityExample>
{
    using Scalar = GetPropType<TypeTag, Properties::Scalar>;
    using type = FluidSystems::OnePLiquid<Scalar, Components::Constant<1, Scalar> >;
};

// This sets the grid type used for the simulation. Here, we use a structured 2D grid.
template<class TypeTag>
struct Grid<TypeTag, TTag::LidDrivenCavityExample> { using type = Dune::YaspGrid<2>; };

// This sets our problem class (see problem.hh) containing initial and boundary conditions.
template<class TypeTag>
struct Problem<TypeTag, TTag::LidDrivenCavityExample> { using type = Dumux::LidDrivenCavityExampleProblem<TypeTag> ; };
```

We also set some properties related to memory management
throughout the simulation.
<details><summary> Click to show caching properties</summary>

In Dumux, one has the option to activate/deactivate the grid-wide caching of
geometries and variables. If active, the CPU time can be significantly reduced
as less dynamic memory allocation procedures are necessary. Per default, grid-wide
caching is disabled to ensure minimal memory requirements, however, in this example we
want to active all available caches, which significantly increases the memory
demand but makes the simulation faster.


```cpp
// This enables grid-wide caching of the volume variables.
template<class TypeTag>
struct EnableGridGeometryCache<TypeTag, TTag::LidDrivenCavityExample> { static constexpr bool value = true; };
//This enables grid wide caching for the flux variables.
template<class TypeTag>
struct EnableGridFluxVariablesCache<TypeTag, TTag::LidDrivenCavityExample> { static constexpr bool value = true; };
// This enables grid-wide caching for the finite volume grid geometry
template<class TypeTag>
struct EnableGridVolumeVariablesCache<TypeTag, TTag::LidDrivenCavityExample> { static constexpr bool value = true; };
} // end namespace Dumux::Properties
```

</details>

</details>



## Initial and boundary conditions (`problem.hh`)

This file contains the __problem class__ which defines the initial and boundary
conditions for the Navier-Stokes single-phase flow simulation.


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


### Include files


```cpp
#include <dumux/common/properties.hh>
#include <dumux/common/parameters.hh>
```

Include the `NavierStokesProblem` class, the base
class from which we will derive.

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

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

```cpp
#include <dumux/freeflow/navierstokes/boundarytypes.hh>
```

### The problem class
As we are solving a problem related to free flow, we create a new class called `LidDrivenCavityExampleProblem`
and let it inherit from the class `NavierStokesProblem`.

```cpp
namespace Dumux {
template <class TypeTag>
class LidDrivenCavityExampleProblem : public NavierStokesProblem<TypeTag>
{
    using ParentType = NavierStokesProblem<TypeTag>;

    using BoundaryTypes = Dumux::NavierStokesBoundaryTypes<GetPropType<TypeTag, Properties::ModelTraits>::numEq()>;
    using GridGeometry = GetPropType<TypeTag, Properties::GridGeometry>;
    using FVElementGeometry = typename GridGeometry::LocalView;
    using SubControlVolume = typename GridGeometry::SubControlVolume;
    using Indices = typename GetPropType<TypeTag, Properties::ModelTraits>::Indices;
    using NumEqVector = GetPropType<TypeTag, Properties::NumEqVector>;
    using PrimaryVariables = GetPropType<TypeTag, Properties::PrimaryVariables>;
    using Scalar = GetPropType<TypeTag, Properties::Scalar>;

    using Element = typename GridGeometry::GridView::template Codim<0>::Entity;
    using GlobalPosition = typename Element::Geometry::GlobalCoordinate;

public:
    // Within the constructor, we set the lid velocity to a run-time specified value.
    LidDrivenCavityExampleProblem(std::shared_ptr<const GridGeometry> gridGeometry)
    : ParentType(gridGeometry)
    {
        lidVelocity_ = getParam<Scalar>("Problem.LidVelocity");
    }
```

#### Temperature distribution
We need to specify a constant temperature for our isothermal problem.
Fluid properties that depend on temperature will be calculated with this value.
This would be important if another fluidsystem was used.

```cpp
    Scalar temperature() const
    { return 273.15 + 10; } // 10°C
```

#### Boundary conditions
With the following function we define the __type of boundary conditions__ depending on the location.
Three types of boundary conditions can be specified: Dirichlet, Neumann or outflow boundary conditions. On
Dirichlet boundaries, the values of the primary variables need to be fixed. On a Neumann boundaries,
values for derivatives need to be fixed. Outflow conditions set a gradient of zero in normal direction towards the boundary
for the respective primary variables (excluding pressure).
When Dirichlet conditions are set for the pressure, the velocity gradient
with respect to the direction normal to the boundary is automatically set to zero.

```cpp
    BoundaryTypes boundaryTypesAtPos(const GlobalPosition &globalPos) const
    {
        BoundaryTypes values;

        // We set Dirichlet values for the velocity at each boundary
        values.setDirichlet(Indices::velocityXIdx);
        values.setDirichlet(Indices::velocityYIdx);

        return values;
    }
```

We define a function for setting a fixed Dirichlet pressure value at a given internal cell.
This is required for having a defined pressure level in our closed system domain.

```cpp
    bool isDirichletCell(const Element& element,
                         const FVElementGeometry& fvGeometry,
                         const SubControlVolume& scv,
                         int pvIdx) const
    {
        auto isLowerLeftCell = [&](const SubControlVolume& scv)
        { return scv.dofIndex() == 0; };
```

We set a fixed pressure in one cell

```cpp
        return (isLowerLeftCell(scv) && pvIdx == Indices::pressureIdx);
    }
```

The following function specifies the __values on Dirichlet boundaries__.
We need to define values for the primary variables (velocity and pressure).

```cpp
    PrimaryVariables dirichletAtPos(const GlobalPosition &globalPos) const
    {
        PrimaryVariables values;
        values[Indices::pressureIdx] = 1.1e+5;
        values[Indices::velocityXIdx] = 0.0;
        values[Indices::velocityYIdx] = 0.0;

        // We set the no slip-condition at the top, that means the fluid has the same velocity as the lid
        if (globalPos[1] > this->gridGeometry().bBoxMax()[1] - eps_)
            values[Indices::velocityXIdx] = lidVelocity_;

        return values;
    }
```

The following function defines the initial conditions.

```cpp
    PrimaryVariables initialAtPos(const GlobalPosition &globalPos) const
    {
        PrimaryVariables values;
        values[Indices::pressureIdx] = 1.0e+5;
        values[Indices::velocityXIdx] = 0.0;
        values[Indices::velocityYIdx] = 0.0;

        return values;
    }
```

the data members of the problem class

```cpp
private:
    static constexpr Scalar eps_ = 1e-6;
    Scalar lidVelocity_;
};

} // end namespace Dumux
```


</details>



## The main file (`main.cc`)

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


### Included header files
<details><summary> Click to show includes</summary>
These is DUNE helper class related to parallel computation

```cpp
#include <dune/common/parallel/mpihelper.hh>
```

The following headers include functionality related to property definition or retrieval, as well as
the retrieval of input parameters specified in the input file or via the command line.

```cpp
#include <dumux/common/parameters.hh>
#include <dumux/common/properties.hh>
```

The following files contain the non-linear Newton solver, the available linear solver backends and the assembler for the linear
systems arising from the staggered-grid discretization.

```cpp
#include <dumux/linear/seqsolverbackend.hh>
#include <dumux/nonlinear/newtonsolver.hh>
#include <dumux/assembly/staggeredfvassembler.hh>
```

The gridmanager constructs a grid from the information in the input or grid file.
Many different Dune grid implementations are supported, of which a list can be found
in `gridmanager.hh`.

```cpp
#include <dumux/io/grid/gridmanager_yasp.hh>
```

This class contains functionality for VTK output for models using the staggered finite volume scheme.

```cpp
#include <dumux/io/staggeredvtkoutputmodule.hh>
```

We include the problem header used for this simulation.

```cpp
#include "properties.hh"
```

</details>

The following function writes the velocities and coordinates at x = 0.5 and y = 0.5 into a log file.

```cpp
template<class Problem, class SolutionVector, class GridGeometry>
void writeSteadyVelocityAndCoordinates(const Problem& problem, const SolutionVector &sol, const GridGeometry gridGeometry)
{
    std::ofstream logFilevx(problem->name() + "_vx.log"), logFilevy(problem->name() + "_vy.log");
    logFilevx << "y vx\n";
    logFilevy << "x vy\n";

    static constexpr double eps_ = 1.0e-7;
    for (const auto& element : elements(gridGeometry->gridView()))
    {
        auto fvGeometry = localView(*gridGeometry);
        fvGeometry.bind(element);
        for (const auto& scvf : scvfs(fvGeometry))
        {
            if (!scvf.boundary() && scvf.insideScvIdx() > scvf.outsideScvIdx())
            {
                const auto& globalPos = scvf.ipGlobal();
                const auto velocity = sol[gridGeometry->faceIdx()][scvf.dofIndex()][0];

                if (std::abs(globalPos[0]-0.5) < eps_)
                    logFilevx << globalPos[1] << " " << velocity << "\n";
                else if (std::abs(globalPos[1]-0.5) < eps_)
                    logFilevy << globalPos[0] << " " << velocity << "\n";
            }
        }
    }
}
```

### The main function
We will now discuss the main program flow implemented within the `main` function.
At the beginning of each program using Dune, an instance of `Dune::MPIHelper` has to
be created. Moreover, we parse the run-time arguments from the command line and the
input file:

```cpp
int main(int argc, char** argv)
{
    using namespace Dumux;

    // The Dune MPIHelper must be instantiated for each program using Dune, it is finalized automatically on exit
    const auto& mpiHelper = Dune::MPIHelper::instance(argc, argv);

    // parse command line arguments and input file
    Parameters::init(argc, argv);
```

We define a convenience alias for the type tag of the problem. The type
tag contains all the properties that are needed to define the model and the problem
setup. Throughout the main file, we will obtain types defined for this type tag
using the property system, i.e. with `GetPropType`.

```cpp
    using TypeTag = Properties::TTag::LidDrivenCavityExample;
```

#### Step 1: Create the grid
The `GridManager` class creates the grid from information given in the input file.
This can either be a grid file, or in the case of structured grids, one can specify the coordinates
of the corners of the grid and the number of cells to be used to discretize each spatial direction.

```cpp
    GridManager<GetPropType<TypeTag, Properties::Grid>> gridManager;
    gridManager.init();

    // We compute on the leaf grid view.
    const auto& leafGridView = gridManager.grid().leafGridView();
```

#### Step 2: Setting up and solving the problem
First, a finite volume grid geometry is constructed from the grid that was created above.
This builds the sub-control volumes (scv) and sub-control volume faces (scvf) for each element
of the grid partition.

```cpp
    using GridGeometry = GetPropType<TypeTag, Properties::GridGeometry>;
    auto gridGeometry = std::make_shared<GridGeometry>(leafGridView);
    gridGeometry->update();
```

We now instantiate the problem, in which we define the boundary and initial conditions.

```cpp
    using Problem = GetPropType<TypeTag, Properties::Problem>;
    auto problem = std::make_shared<Problem>(gridGeometry);
```

We set a solution vector which consist of two parts: one part (indexed by `cellCenterIdx`)
is for the pressure degrees of freedom (`dofs`) living in grid cell centers. Another part
(indexed by `faceIdx`) is for degrees of freedom defining the normal velocities on grid cell faces.
We initialize the solution vector by what was defined as the initial solution of the the problem.

```cpp
    using SolutionVector = GetPropType<TypeTag, Properties::SolutionVector>;
    SolutionVector x;
    x[GridGeometry::cellCenterIdx()].resize(gridGeometry->numCellCenterDofs());
    x[GridGeometry::faceIdx()].resize(gridGeometry->numFaceDofs());
    problem->applyInitialSolution(x);
    auto xOld = x;
```

We use the initial solution vector to intialize the `gridVariables`.
The grid variables are used store variables (primary and secondary variables) on sub-control volumes and faces (volume and flux variables).

```cpp
    using GridVariables = GetPropType<TypeTag, Properties::GridVariables>;
    auto gridVariables = std::make_shared<GridVariables>(problem, gridGeometry);
    gridVariables->init(x);
```

We get some time loop parameters from the input file
and instantiate the time loop

```cpp
    using Scalar = GetPropType<TypeTag, Properties::Scalar>;
    const auto tEnd = getParam<Scalar>("TimeLoop.TEnd");
    const auto maxDt = getParam<Scalar>("TimeLoop.MaxTimeStepSize");
    const auto dt = getParam<Scalar>("TimeLoop.DtInitial");

    auto timeLoop = std::make_shared<TimeLoop<Scalar>>(0, dt, tEnd);
    timeLoop->setMaxTimeStepSize(maxDt);
```

We then initialize the predefined model-specific output vtk output.

```cpp
    using IOFields = GetPropType<TypeTag, Properties::IOFields>;
    StaggeredVtkOutputModule<GridVariables, SolutionVector> vtkWriter(*gridVariables, x, problem->name());
    IOFields::initOutputModule(vtkWriter); // Add model specific output fields
    vtkWriter.write(0.0);
```

To solve the non-linear problem at hand, we use the `NewtonSolver`,
which we have to tell how to assemble and solve the system in each
iteration. Here, we use the direct linear solver UMFPack.

```cpp
    using Assembler = StaggeredFVAssembler<TypeTag, DiffMethod::numeric>;
    auto assembler = std::make_shared<Assembler>(problem, gridGeometry, gridVariables, timeLoop, xOld);

    using LinearSolver = Dumux::UMFPackBackend;
    auto linearSolver = std::make_shared<LinearSolver>();

    using NewtonSolver = Dumux::NewtonSolver<Assembler, LinearSolver>;
    NewtonSolver nonLinearSolver(assembler, linearSolver);
```

##### The time loop
In each time step, we solve the non-linear system of equations, write
the current solution into .vtk files and prepare for the next time step.

```cpp
    timeLoop->start(); do
    {
        // We solve the non-linear system with time step control.
        nonLinearSolver.solve(x, *timeLoop);

        // We make the new solution the old solution.
        xOld = x;
        gridVariables->advanceTimeStep();

        // We advance to the time loop to the next step.
        timeLoop->advanceTimeStep();

        // We write vtk output for each time step.
        vtkWriter.write(timeLoop->time());

        // We report statistics of this time step.
        timeLoop->reportTimeStep();

        // We set a new dt as suggested by the newton solver for the next time step.
        timeLoop->setTimeStepSize(nonLinearSolver.suggestTimeStepSize(timeLoop->timeStepSize()));

    } while (!timeLoop->finished());
```

We write the velocities and coordinates at x = 0.5 and y = 0.5 into a file

```cpp
    writeSteadyVelocityAndCoordinates(problem, x, gridGeometry);
```

The following piece of code prints a final status report of the time loop
before the program is terminated.

```cpp
    timeLoop->finalize(leafGridView.comm());

    // print used and unused parameters
    if (mpiHelper.rank() == 0)
        Parameters::print();

    return 0;
} // end main
```


</details>


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

