<!-- 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 2p set-up

The two-phase flow set-up is implemented in the files `properties.hh`,
`problem.hh` and `spatialparams.hh`. In the file `problem.hh` a description of the boundary and initial conditions can be found. Additionally, you can see how to implement an injection well as a point source and how to read the initial solution from a text file. In the file `spatialparams.hh` we create a lens within the porous medium, that has different spatial parameters than the surrounding material and set the parameters for the
$`p_c - S_w`$ relationship.

[[_TOC_]]


## The file `properties.hh`

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


### Includes
The header includes will be mentioned in the text below.
<details><summary> Click to show header includes</summary>

```cpp

#include <dune/alugrid/grid.hh>

#include <dumux/common/properties.hh>
#include <dumux/discretization/cctpfa.hh>
#include <dumux/porousmediumflow/2p/model.hh>

#include <dumux/material/components/trichloroethene.hh>
#include <dumux/material/components/simpleh2o.hh>
#include <dumux/material/fluidsystems/1pliquid.hh>
#include <dumux/material/fluidsystems/2pimmiscible.hh>

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

</details>

### Type tag definition
All properties are defined in the (nested) namespace
`Dumux::Properties`. To get and set properties, we need the definitions and implementations from the
header `dumux/common/properties.hh` included above.

```cpp
namespace Dumux::Properties {
```

First, a so-called TypeTag is created. Properties are traits specialized for this TypeTag (a simple `struct`).

>>>
:white_check_mark: The properties of other TypeTags are inherited if the alias `InheritsFrom` is present.
These other TypeTags are listed in form of a `std::tuple` in order of importance.
>>>

Here, properties from the two-phase flow model (`TTag::Twop`) and the
cell-centered finite volume scheme with two-point-flux approximation (`TTag::CCTpfaModel`)
are inherited. These other TypeTag definitions can be found in the included
headers `dumux/porousmediumflow/2p/model.hh` and `dumux/discretization/cctpfa.hh`.

```cpp
namespace TTag {
struct PointSourceExample { using InheritsFrom = std::tuple<TwoP, CCTpfaModel>; };
}
```

### Property specializations
Next, we specialize the properties `Problem` and `SpatialParams` for our new TypeTag 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::PointSourceExample>
{ using type = PointSourceProblem<TypeTag>; };

template<class TypeTag>
struct SpatialParams<TypeTag, TTag::PointSourceExample>
{
    // two local aliases for convenience and readability
    using GridGeometry = GetPropType<TypeTag, Properties::GridGeometry>;
    using Scalar = GetPropType<TypeTag, Properties::Scalar>;

    using type = TwoPTestSpatialParams<GridGeometry, Scalar>;
};
```

The `Grid` property tells the
simulator to use ALUGrid - an unstructured grid manager - here
configured for grid and coordinate dimensions `2`,
hexahedral element types (`Dune::cube`) and non-conforming refinement mode.
`Dune::ALUGrid` is declared in the included header `dune/alugrid/grid.hh`
from the Dune module `dune-alugrid`.

```cpp
template<class TypeTag>
struct Grid<TypeTag, TTag::PointSourceExample>
{ using type = Dune::ALUGrid<2, 2, Dune::cube, Dune::nonconforming>; };
```

The `FluidSystem` property specifies which fluids are used.
This fluid system is composed of two immiscible liquid phases which are made up
entirely of its respective main components `SimpleH2O` (a water component with constant properties)
and `Trichloroethene` (a DNAPL). The components, phases, and the fluid system are implemented in
the headers `dumux/material/components/simpleh2o.hh`,
`dumux/material/components/trichloroethene.hh`,
`dumux/material/fluidsystems/1pliquid.hh`,
`dumux/material/fluidsystems/2pimmiscible.hh`
included above.

```cpp
template<class TypeTag>
struct FluidSystem<TypeTag, TTag::PointSourceExample>
{
  using Scalar = GetPropType<TypeTag, Properties::Scalar>;
  using WettingPhase = FluidSystems::OnePLiquid<Scalar, Components::SimpleH2O<Scalar> >;
  using NonwettingPhase = FluidSystems::OnePLiquid<Scalar, Components::Trichloroethene<Scalar> >;

  using type = FluidSystems::TwoPImmiscible<Scalar, WettingPhase, NonwettingPhase>;
};
```

The two-phase model implements different primary variable formulations.
Here we choose the pressure of the first phase and the saturation of the second phase.
The order of phases is specified by the fluid system.
In this case that means that the primary variables are water pressure and DNAPL saturation.

```cpp
template<class TypeTag>
struct Formulation<TypeTag, TTag::PointSourceExample>
{ static constexpr auto value = TwoPFormulation::p0s1; };

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


</details>



## The file `problem.hh`

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


### Includes
We start with includes for `PorousMediumFlowProblem`, `readFileToContainer`,
`BoundaryTypes` and `GetPropType` (used below).

```cpp
#include <dumux/porousmediumflow/problem.hh>
#include <dumux/io/container.hh>
#include <dumux/common/boundarytypes.hh>
#include <dumux/common/properties.hh>
```

### Problem class
The problem class `PointSourceProblem` implements boundary and initial conditions.
It derives from the `PorousMediumFlowProblem` class.

```cpp
namespace Dumux {

template <class TypeTag>
class PointSourceProblem : public PorousMediumFlowProblem<TypeTag>
{
```

The class implementation starts with some alias declarations and index definitions for convenience
<details><summary> Click to show local alias declarations and indices</summary>

```cpp

    using ParentType = PorousMediumFlowProblem<TypeTag>;
    using GridGeometry = GetPropType<TypeTag, Properties::GridGeometry>;
    using GridView = typename GridGeometry::GridView;
    using Element = typename GridView::template Codim<0>::Entity;
    using Vertex = typename GridView::template Codim<GridView::dimensionworld>::Entity;
    using Scalar = GetPropType<TypeTag, Properties::Scalar>;
    using FluidSystem = GetPropType<TypeTag, Properties::FluidSystem>;
    using PrimaryVariables = GetPropType<TypeTag, Properties::PrimaryVariables>;
    using PointSource =  GetPropType<TypeTag, Properties::PointSource>;
    using BoundaryTypes = Dumux::BoundaryTypes<PrimaryVariables::size()>;
    using GlobalPosition = typename Element::Geometry::GlobalCoordinate;
    using NumEqVector = GetPropType<TypeTag, Properties::NumEqVector>;
    using Indices = typename GetPropType<TypeTag, Properties::ModelTraits>::Indices;

    enum {
        pressureH2OIdx = Indices::pressureIdx,
        saturationDNAPLIdx = Indices::saturationIdx,
        contiDNAPLEqIdx = Indices::conti0EqIdx + FluidSystem::comp1Idx,
        waterPhaseIdx = FluidSystem::phase0Idx,
        dnaplPhaseIdx = FluidSystem::phase1Idx
    };
```

</details>

In the constructor of the class, we call the parent type's constructor
and read the intial values for the primary variables from a text file.
The function `readFileToContainer` is implemented in the header `dumux/io/container.hh`.

```cpp
public:
    PointSourceProblem(std::shared_ptr<const GridGeometry> gridGeometry)
    : ParentType(gridGeometry)
    {
        initialValues_ = readFileToContainer<std::vector<PrimaryVariables>>("initialsolutioncc.txt");
    }
```

For isothermal problems, Dumux requires problem classes to implement a `temperature()`
member function. Fluid properties that depend on temperature will be calculated with the specified temperature.

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

#### Boundary types
We define the type of boundary conditions depending on location. Two types of boundary conditions
can be specified: Dirichlet or Neumann boundary condition. On a Dirichlet boundary, the values of the
primary variables need to be fixed. On a Neumann boundary condition, values for derivatives need to be fixed.
Mixed boundary conditions (different types for different equations on the same boundary) are not accepted.

```cpp
    BoundaryTypes boundaryTypesAtPos(const GlobalPosition &globalPos) const
    {
        BoundaryTypes values;
        // Dirichlet boundaries on the left and right hand side of the domain
        if (onLeftBoundary_(globalPos) || onRightBoundary_(globalPos))
            values.setAllDirichlet();
        // and Neumann boundaries otherwise (top and bottom of the domain)
        else
            values.setAllNeumann();
        return values;
    }
```

#### Dirichlet boundaries
We specify the values for the Dirichlet boundaries, depending on location.
We need to fix values for the two primary variables: the water pressure
and the DNAPL saturation.

```cpp
    PrimaryVariables dirichletAtPos(const GlobalPosition &globalPos) const
    {
        // To determine the density of water for a given state, we build a fluid state with the given conditions:
        PrimaryVariables values;
        GetPropType<TypeTag, Properties::FluidState> fluidState;
        fluidState.setTemperature(temperature());
        fluidState.setPressure(waterPhaseIdx, /*pressure=*/1e5);
        fluidState.setPressure(dnaplPhaseIdx, /*pressure=*/1e5);

        // The density is then calculated by the fluid system:
        const Scalar densityW = FluidSystem::density(fluidState, waterPhaseIdx);

        // The water phase pressure is the hydrostatic pressure, scaled with a factor:
        const Scalar height = this->gridGeometry().bBoxMax()[1] - this->gridGeometry().bBoxMin()[1];
        const Scalar depth = this->gridGeometry().bBoxMax()[1] - globalPos[1];
        const Scalar alpha = 1 + 1.5/height;
        const Scalar width = this->gridGeometry().bBoxMax()[0] - this->gridGeometry().bBoxMin()[0];
        const Scalar factor = (width*alpha + (1.0 - alpha)*globalPos[0])/width;

        values[pressureH2OIdx] = 1e5 - factor*densityW*this->spatialParams().gravity(globalPos)[1]*depth;
        // The saturation of the DNAPL Trichlorethene is zero on our Dirichlet boundary:
        values[saturationDNAPLIdx] = 0.0;

        return values;
    }
```

#### Neumann boundaries
In our case, we need to specify mass fluxes for our two liquid phases.
Negative sign means influx and the unit of the boundary flux is $`kg/(m^2 s)`$.
On the inlet area, we set a DNAPL influx of $`0.04 kg/(m^2 s)`$. On all other
Neumann boundaries, the boundary flux is zero.

```cpp
    NumEqVector neumannAtPos(const GlobalPosition &globalPos) const
    {
        NumEqVector values(0.0);
        if (onInlet_(globalPos))
            values[contiDNAPLEqIdx] = -0.04;

        return values;
    }
```

#### Initial conditions
The initial condition needs to be set for all primary variables.
Here, we take the data from the file that we read in previously.

```cpp
    PrimaryVariables initial(const Element& element) const
    {
        // The input data is written for a uniform grid with discretization length delta.
        // Accordingly, we need to find the index of our cells, depending on the x and y coordinates,
        // that corresponds to the indices of the input data set.
        const auto delta = 0.0625;
        const unsigned int cellsX = this->gridGeometry().bBoxMax()[0]/delta;
        const auto globalPos = element.geometry().center();

        const unsigned int dataIdx = std::trunc(globalPos[1]/delta) * cellsX + std::trunc(globalPos[0]/delta);
        return initialValues_[dataIdx];
    }
```

#### Point source
In this scenario, we set a point source (e.g. modeling a well). The point source value can be solution dependent.
Point sources are added by pushing them into the vector `pointSources`.
The `PointSource` constructor takes two arguments.
The first argument is a coordinate array containing the position in space,
the second argument is an array of source value for each equation (in units of $`kg/s`$).
Recall that the first eqution is the water phase mass balance
and the second equation is the DNAPL phase mass balance.

```cpp
    void addPointSources(std::vector<PointSource>& pointSources) const
    {
        pointSources.push_back(PointSource({0.502, 3.02}, {0, 0.1}));
    }
```

In the private part of the class, we define some helper functions for
the boundary conditions and local variables.
<details><summary> Click to show private data members and functions</summary>

```cpp

private:
    bool onLeftBoundary_(const GlobalPosition &globalPos) const
    { return globalPos[0] < this->gridGeometry().bBoxMin()[0] + eps_; }

    bool onRightBoundary_(const GlobalPosition &globalPos) const
    { return globalPos[0] > this->gridGeometry().bBoxMax()[0] - eps_; }

    bool onUpperBoundary_(const GlobalPosition &globalPos) const
    { return globalPos[1] > this->gridGeometry().bBoxMax()[1] - eps_; }

    bool onInlet_(const GlobalPosition &globalPos) const
    {
        Scalar width = this->gridGeometry().bBoxMax()[0] - this->gridGeometry().bBoxMin()[0];
        Scalar lambda = (this->gridGeometry().bBoxMax()[0] - globalPos[0])/width;
        return onUpperBoundary_(globalPos) && 0.5 < lambda && lambda < 2.0/3.0;
    }

    static constexpr Scalar eps_ = 1e-6;
    std::vector<PrimaryVariables> initialValues_;
};

} // end namespace Dumux
```

</details>

</details>



## The file `spatialparams.hh`

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


### Includes
We include the basic spatial parameters for finite volumes file from which we will inherit

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

We include all laws which are needed to define the interaction between the solid matrix and the fluids, e.g. laws for capillary pressure saturation relationships.

```cpp
#include <dumux/material/fluidmatrixinteractions/2p/vangenuchten.hh>
```

### The spatial parameters class
In the TwoPTestSpatialParams class we define all functions needed to describe the porous matrix, e.g. porosity and permeability. We inherit from the `FVSpatialParams` class, which is the base class for multiphase porous medium flow applications.

```cpp
namespace Dumux {

template<class GridGeometry, class Scalar>
class TwoPTestSpatialParams
: public FVSpatialParams<GridGeometry, Scalar, TwoPTestSpatialParams<GridGeometry, Scalar>>
{
    //we introduce using declarations that are derived from the property system which we need in this class
    using GridView = typename GridGeometry::GridView;
    using Element = typename GridView::template Codim<0>::Entity;
    using FVElementGeometry = typename GridGeometry::LocalView;
    using SubControlVolume = typename FVElementGeometry::SubControlVolume;
    using ThisType = TwoPTestSpatialParams<GridGeometry, Scalar>;
    using ParentType = FVSpatialParams<GridGeometry, Scalar, ThisType>;

    static constexpr int dimWorld = GridView::dimensionworld;
    using GlobalPosition = typename Element::Geometry::GlobalCoordinate;

    using PcKrSwCurve = FluidMatrix::VanGenuchtenDefault<Scalar>;

public:
    using PermeabilityType = Scalar;
```

Here, we get parameters for the position of the lens and porosity and permeability from the input file. Additionally, we set the parameters for the Van-Genuchten relationship.

```cpp
    TwoPTestSpatialParams(std::shared_ptr<const GridGeometry> gridGeometry)
    : ParentType(gridGeometry)
    , pcKrSwLens_("SpatialParams.Lens") // read params from input file
    , pcKrSwOuter_("SpatialParams.Outer") // read params from input file
    {
        // We get the position of the lens from the params.input file.
        // The lens is defined by the position of the lower left and the upper right corner
        lensLowerLeft_ = getParam<GlobalPosition>("SpatialParams.LensLowerLeft");
        lensUpperRight_ = getParam<GlobalPosition>("SpatialParams.LensUpperRight");

        // Here, we get the permeabilities from the params.input file.
        // In case that no parameter is set, the default parameters (9.05e-12 and 4.6e-10) are used
        lensK_ = getParam<Scalar>("SpatialParams.Lens.Permeability", 9.05e-12);
        outerK_ = getParam<Scalar>("SpatialParams.Outer.Permeability", 4.6e-10);
    }
```

We define the (intrinsic) permeability $`[m^2]`$. In this test, we use element-wise distributed permeabilities.

```cpp
    template<class ElementSolution>
    PermeabilityType permeability(const Element& element,
                                  const SubControlVolume& scv,
                                  const ElementSolution& elemSol) const
    {
        if (isInLens_(element.geometry().center()))
            return lensK_;
        return outerK_;
    }
```

We set the porosity $`[-]`$ depending on the position

```cpp
    Scalar porosityAtPos(const GlobalPosition& globalPos) const
    {
         if (isInLens_(globalPos))
            return 0.2;
        return 0.4;
    }
```

We set the parameter object for the Van Genuchten material law.

```cpp
    template<class ElementSolution>
    auto fluidMatrixInteraction(const Element& element,
                                const SubControlVolume& scv,
                                const ElementSolution& elemSol) const
    {
        if (isInLens_(element.geometry().center()))
            return makeFluidMatrixInteraction(pcKrSwLens_);
        return makeFluidMatrixInteraction(pcKrSwOuter_);
    }
```

Here we can define which phase is to be considered as the wetting phase. Here the wetting phase is the the first phase of the fluidsystem. In this case that is water.

```cpp
    template<class FluidSystem>
    int wettingPhaseAtPos(const GlobalPosition& globalPos) const
    {  return FluidSystem::phase0Idx; }
```

The remainder of this class contains a convenient function to determine if
a position is inside the lens and defines the data members.
<details><summary> Click to show private data members and member functions</summary>

```cpp
private:
    // we have a convenience definition of the position of the lens
    bool isInLens_(const GlobalPosition &globalPos) const
    {
        for (int i = 0; i < dimWorld; ++i) {
            if (globalPos[i] < lensLowerLeft_[i] + eps_ || globalPos[i] > lensUpperRight_[i] - eps_)
                return false;
        }
        return true;
    }

    GlobalPosition lensLowerLeft_;
    GlobalPosition lensUpperRight_;

    Scalar lensK_;
    Scalar outerK_;

    const PcKrSwCurve pcKrSwLens_;
    const PcKrSwCurve pcKrSwOuter_;

    static constexpr Scalar eps_ = 1.5e-7;
};

} // end namespace Dumux
```

</details>

</details>


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

