<!-- 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_left: Go back to part 1](1p.md) | [:arrow_right: Continue with part 3](main.md) |
|---|---|---:|

# Part 2: Implementation of the tracer transport simulation setup

The tracer transport setup is implemented in the files `properties_tracer.hh`,
`problem_tracer.hh` and `spatialparams_tracer.hh`. In the first of these files, a new
`TypeTag` is declared for this problem. This then allows the specialization
of DuMuX `properties` for this new `TypeTag`, 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. porosity and permeability) that should be used by the model.

The documentation provided in the sequel is structured as follows:

[[_TOC_]]


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

This file defines the type tag used for the tracer transport simulation, 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_tracer.hh))</summary>


### Includes
<details><summary> Click to show includes</summary>
As for the single-phase problem, atype tag is defined also for this simulation.
Here, we inherit all properties of the `Tracer` type tag, a convenience type tag
that specializes most of the required properties for tracer transport flow simulations in DuMuX.

```cpp
#include <dumux/porousmediumflow/tracer/model.hh>
```

We use YaspGrid, an implementation of the dune grid interface for structured grids.

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

We want to discretize the equations with the cell centered finite volume scheme using
two-point-flux approximation.

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

This includes the base class for fluid systems. We will define a custom fluid
system that inherits from that class.

```cpp
#include <dumux/material/fluidsystems/base.hh>
```

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

```cpp
#include "problem_tracer.hh"
#include "spatialparams_tracer.hh"
```

</details>

### Definition of a custom fluid system

In the following, we define a new tracer fluid system that contains a single component
with a molar mass of 0.3 kg/mol. This fluid system derives from the base class for
fluid systems `FluidSystems::Base`.

```cpp
namespace Dumux {

// In the following, we create a new tracer fluid system and derive from the base fluid system.
template<class TypeTag>
class TracerFluidSystem : public FluidSystems::Base<GetPropType<TypeTag, Properties::Scalar>,
                                                               TracerFluidSystem<TypeTag>>
{
    // Some convenience aliases to be used inside this class.
    using Scalar = GetPropType<TypeTag, Properties::Scalar>;
    using Problem = GetPropType<TypeTag, Properties::Problem>;
    using GridView = typename GetPropType<TypeTag, Properties::GridGeometry>::GridView;
    using Element = typename GridView::template Codim<0>::Entity;
    using FVElementGeometry = typename GetPropType<TypeTag, Properties::GridGeometry>::LocalView;
    using SubControlVolume = typename FVElementGeometry::SubControlVolume;

public:
    // We specify that the fluid system only contains tracer components,
    static constexpr bool isTracerFluidSystem()
    { return true; }

    // We define the number of components of this fluid system (one single tracer component)
    static constexpr int numComponents = 1;

    // This interface is designed to define the names of the components of the fluid system.
    // Here, we only have a single component, so `compIdx` should always be 0.
    // The component name is used for the vtk output.
    static std::string componentName(int compIdx = 0)
    { return "tracer_" + std::to_string(compIdx); }

    // We set the phase name for the phase index (`phaseIdx`) for velocity vtk output:
    // Here, we only have a single phase, so `phaseIdx` should always be zero.
    static std::string phaseName(int phaseIdx = 0)
    { return "Groundwater"; }

    // We set the molar mass of the tracer component with index `compIdx` (should again always be zero here).
    static Scalar molarMass(unsigned int compIdx = 0)
    { return 0.300; }

    // We set the value for the binary diffusion coefficient. This
    // might depend on spatial parameters like pressure / temperature.
    // But, in this case we neglect diffusion and return 0.0.
    static Scalar binaryDiffusionCoefficient(unsigned int compIdx,
                                             const Problem& problem,
                                             const Element& element,
                                             const SubControlVolume& scv)
    { return 0.0; }
};
```


### Type tag definition

We define a type tag for our simulation with the name `TracerTest` and inherit
the properties specialized for the type tags `Tracer` and `CCTpfaModel`.
This way, most of the properties required for tracer transport simulations using
the cell centered finite volume scheme with two-point-flux approximation are
conveniently specialized for our new type tag.
However, some properties depend on user choices and no meaningful default value
can be set. Those properties will be adressed later in this file.

```cpp
namespace Properties {

// declaration of the `TracerTest` type tag for the tracer transport problem
namespace TTag {
struct TracerTest { using InheritsFrom = std::tuple<Tracer, CCTpfaModel>; };
}
```


### Property specializations

In the following piece of code, mandatory properties for which no meaningful
default can be set, are specialized for our type tag `TracerTest`.

```cpp
// We use the same grid type as in the stationary one-phase model, a structured 2D grid.
template<class TypeTag>
struct Grid<TypeTag, TTag::TracerTest> { using type = Dune::YaspGrid<2>; };

// This sets our problem class (see problem_tracer.hh) that specifies initial and boundary conditions.
template<class TypeTag>
struct Problem<TypeTag, TTag::TracerTest> { using type = TracerTestProblem<TypeTag>; };

// This defines the spatial parameters class (spatialparams_tracer.hh) for our tracer simulation.
template<class TypeTag>
struct SpatialParams<TypeTag, TTag::TracerTest>
{
private:
    using GridGeometry = GetPropType<TypeTag, Properties::GridGeometry>;
    using Scalar = GetPropType<TypeTag, Properties::Scalar>;
public:
    using type = TracerTestSpatialParams<GridGeometry, Scalar>;
};

// We set the tracer fluid system that we have defined above.
template<class TypeTag>
struct FluidSystem<TypeTag, TTag::TracerTest> { using type = TracerFluidSystem<TypeTag>; };
```


The above are all mandatory properties, however, we also specialize the `UseMoles`
property, which can be used to switch between mole or mass balances to be solved
in compositional models. It defaults to `true`, and thus, to a molar formulation,
and we set it to `false` here to specify that we want to solve the mass balance
equation for the tracer component.

```cpp
template<class TypeTag>
struct UseMoles<TypeTag, TTag::TracerTest> { static constexpr bool value = false; };
```

Moreover, we specialize several properties related to efficiency optimizations
<details><summary> Click to show caching properties</summary>

```cpp
// In Dumux, one has the option to activate/deactive 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 significanlty increases the memory demand but makes the simulation faster
template<class TypeTag>
struct EnableGridVolumeVariablesCache<TypeTag, TTag::TracerTest> { static constexpr bool value = true; };
template<class TypeTag>
struct EnableGridFluxVariablesCache<TypeTag, TTag::TracerTest> { static constexpr bool value = true; };
template<class TypeTag>
struct EnableGridGeometryCache<TypeTag, TTag::TracerTest> { static constexpr bool value = true; };

// We use solution-independent molecular diffusion coefficients. Per default, solution-dependent
// diffusion coefficients are assumed during the computation of the jacobian matrix entries. Specifying
// solution-independent diffusion coefficients can speed up computations significantly.
template<class TypeTag>
struct SolutionDependentMolecularDiffusion<TypeTag, TTag::TracerTest>
{ static constexpr bool value = false; };

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

</details>

</details>



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

This file contains the __problem class__ which defines the initial and boundary
conditions for the tracer transport simulation.


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


### Include files
Include the `PorousMediumFlowProblem` class, the base
class from which we will derive.

```cpp
#include <dumux/porousmediumflow/problem.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. As we are solving a problem related to
flow in porous media, we inherit from the base class `PorousMediumFlowProblem`.

```cpp
namespace Dumux {

template <class TypeTag>
class TracerTestProblem : public PorousMediumFlowProblem<TypeTag>
{
    // A few convenience aliases used throughout this class.
    using ParentType = PorousMediumFlowProblem<TypeTag>;
    using Scalar = GetPropType<TypeTag, Properties::Scalar>;
    using Indices = typename GetPropType<TypeTag, Properties::ModelTraits>::Indices;
    using GridView = typename GetPropType<TypeTag, Properties::GridGeometry>::GridView;
    using GridGeometry = GetPropType<TypeTag, Properties::GridGeometry>;
    using PrimaryVariables = GetPropType<TypeTag, Properties::PrimaryVariables>;
    using BoundaryTypes = Dumux::BoundaryTypes<PrimaryVariables::size()>;
    using FluidSystem = GetPropType<TypeTag, Properties::FluidSystem>;
    using SpatialParams = GetPropType<TypeTag, Properties::SpatialParams>;
    using Element = typename GridGeometry::GridView::template Codim<0>::Entity;
    using GlobalPosition = typename Element::Geometry::GlobalCoordinate;
    using NumEqVector = GetPropType<TypeTag, Properties::NumEqVector>;
    using GridVariables = GetPropType<TypeTag, Properties::GridVariables>;
    using ElementVolumeVariables = typename GridVariables::GridVolumeVariables::LocalView;
    using ElementFluxVariablesCache = typename GridVariables::GridFluxVariablesCache::LocalView;
    using FVElementGeometry = typename GetPropType<TypeTag, Properties::GridGeometry>::LocalView;
    using SubControlVolumeFace = typename FVElementGeometry::SubControlVolumeFace;
    // We create a convenience bool stating whether mole or mass fractions are used
    static constexpr bool useMoles = getPropValue<TypeTag, Properties::UseMoles>();
    // We create additional convenience integers to make dimWorld and numComponents available in the problem
    static constexpr int dimWorld = GridView::dimensionworld;
    static const int numComponents = FluidSystem::numComponents;

public:
    // This is the constructor of our problem class:
    TracerTestProblem(std::shared_ptr<const GridGeometry> gridGeometry)
    : ParentType(gridGeometry)
    {
        // We print to the terminal whether mole or mass fractions are used
        if(useMoles)
            std::cout<<"problem uses mole fractions" << '\n';
        else
            std::cout<<"problem uses mass fractions" << '\n';
    }
```

#### Boundary conditions

We define the __type of boundary conditions__ depending on the location.
All boundaries are set to a neumann-type flow boundary condition.

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

In the following function we implement the __Neumann boundary conditions__.
Here, we define an outflow boundary on the top of the domain and prescribe zero-flux
Neumann boundary conditions on all other boundaries.

```cpp
    NumEqVector neumann(const Element& element,
                        const FVElementGeometry& fvGeometry,
                        const ElementVolumeVariables& elemVolVars,
                        const ElementFluxVariablesCache& elemFluxVarsCache,
                        const SubControlVolumeFace& scvf) const
    {
        NumEqVector values(0.0);
        const auto& volVars = elemVolVars[scvf.insideScvIdx()];
        const auto& globalPos = scvf.center();

        // This is the outflow boundary, where tracer is transported by advection with the given flux field.
        if (globalPos[dimWorld-1] > this->gridGeometry().bBoxMax()[dimWorld-1] - eps_)
        {
            values = this->spatialParams().volumeFlux(element, fvGeometry, elemVolVars, scvf)
                     * volVars.massFraction(0, 0) * volVars.density(0)
                     / scvf.area();
            assert(values>=0.0 && "Volume flux at outflow boundary is expected to have a positive sign");
        }

        // Prescribe zero-flux Neumann boundary conditions elsewhere
        else
            values = 0.0;

        return values;
    }
```

#### Initial conditions

We specify the initial conditions for the primary variable (tracer mass fraction) depending
on the location. Here, we set zero mass fractions everywhere in the domain except for a strip
at the bottom of the domain where we set an initial mole fraction of $`10^{-9}`$.

```cpp
    PrimaryVariables initialAtPos(const GlobalPosition& globalPos) const
    {
        // initialize the mole fraction to zero
        PrimaryVariables initialValues(0.0);

        // The initial contamination is located at the bottom of the domain
        if (globalPos[1] < 0.1 + eps_)
        {
            // We chose a mole fraction of 1e-9, but in case the mass fractions
            // are used by the model, we have to convert this value:
            if (useMoles)
                initialValues = 1e-9;
            else
                initialValues = 1e-9*FluidSystem::molarMass(0)
                                    /this->spatialParams().fluidMolarMassAtPos(globalPos);
        }

        return initialValues;
    }
```


The remainder of the class contains an epsilon value used for floating point comparisons.

```cpp
private:
    // We assign a private global variable for the epsilon:
    static constexpr Scalar eps_ = 1e-6;

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


</details>



## Parameter distributions (`spatialparams_tracer.hh`)


In this file, we define spatial properties of the porous medium such as permeability
and porosity in various functions for the tracer problem. Furthermore, spatially-dependent
properties of the tracer fluid system are defined as well as functions related to setting
and retrieving the volume fluxes calculated from the solution of the 1p problem.


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


### Include files
We include the spatial parameters class for single-phase models discretized by
finite volume schemes, from which the spatial parameters defined for this example will inherit.

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

### The spatial parameters class

In the OnePTestSpatialParams class, we define all functions needed to define
the spatially-dependent parameters for the tracer problem.
We inherit from the FVSpatialParamsOneP class here, which is the base class for
spatial parameters in the context of single-phase porous medium flow applications
using finite volume discretization schemes.

```cpp
namespace Dumux {

template<class GridGeometry, class Scalar>
class TracerTestSpatialParams
: public FVSpatialParamsOneP<GridGeometry, Scalar,
                             TracerTestSpatialParams<GridGeometry, Scalar>>
{
    using GridView = typename GridGeometry::GridView;
    using FVElementGeometry = typename GridGeometry::LocalView;
    using SubControlVolume = typename FVElementGeometry::SubControlVolume;
    using SubControlVolumeFace = typename FVElementGeometry::SubControlVolumeFace;
    using Element = typename GridView::template Codim<0>::Entity;
    using ParentType = FVSpatialParamsOneP<GridGeometry, Scalar,
                                           TracerTestSpatialParams<GridGeometry, Scalar>>;

    static const int dimWorld = GridView::dimensionworld;
    using GlobalPosition = typename Dune::FieldVector<Scalar, dimWorld>;

public:

    TracerTestSpatialParams(std::shared_ptr<const GridGeometry> gridGeometry)
    : ParentType(gridGeometry) {}
```


#### Properties of the porous matrix
We define the same porosity for the whole domain as in the 1p spatialparams.

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

We do not consider dispersivity for the tracer transport. Thus, we set the
dispersivity coefficient to zero.

```cpp
    template<class ElementSolution>
    Scalar dispersivity(const Element &element,
                        const SubControlVolume& scv,
                        const ElementSolution& elemSol) const
    { return 0; }
```

#### Properties of the fluid phase
In the following, we define fluid phase properties that are spatial parameters
in the tracer model.
They can possible vary in space but are usually constants.
We define the fluid density to a constant value of 1000 $`\frac{kg}{m^3}`$ (liquid water).

```cpp
    Scalar fluidDensity(const Element &element,
                        const SubControlVolume& scv) const
    { return 1000; }
```

The following functions define the molar mass of the fluid phase as function of the
elements of the computational grid and the position in the domain.

```cpp
    // This interface defines the fluid phase's molar mass within the sub-control volume `scv`
    // inside an `element` of the computational grid.
    Scalar fluidMolarMass(const Element& element,
                          const SubControlVolume& scv) const
    { return fluidMolarMassAtPos(scv.dofPosition()); }

    // This interface defines the fluid phase's molar mass depending on the position in the domain.
    Scalar fluidMolarMassAtPos(const GlobalPosition& globalPos) const
    { return 18.0; }
```


#### The volume fluxes
The following function returns the volume flux across the given sub-control volume face `scvf`.
This flux is obtained from the vector `volumeFlux_` that contains the fluxes across al sub-control
volume faces of the discretization. This vector can be set using the `setVolumeFlux` function.

```cpp
    template<class ElementVolumeVariables>
    Scalar volumeFlux(const Element &element,
                      const FVElementGeometry& fvGeometry,
                      const ElementVolumeVariables& elemVolVars,
                      const SubControlVolumeFace& scvf) const
    {
        return volumeFlux_[scvf.index()];
    }
```

This function allows setting the volume fluxes for all sub-control volume faces of the discretization.
This is used in the main function after these fluxes have been based on the pressure solution obtained
with the single-phase model.

```cpp
    void setVolumeFlux(const std::vector<Scalar>& f)
    { volumeFlux_ = f; }
```

The remainder of the class contains the private data members, which in this case
are only the volume fluxes across the sub-control volume faces of the discretization.

```cpp
private:
    std::vector<Scalar> volumeFlux_;
}; // end class definition TracerTestSpatialParams
} // end namespace Dumux
```


</details>


| [:arrow_left: Back to the main documentation](../README.md) | [:arrow_left: Go back to part 1](1p.md) | [:arrow_right: Continue with part 3](main.md) |
|---|---|---:|

