Skip to content
Snippets Groups Projects
Commit 3bb596eb authored by Kilian Weishaupt's avatar Kilian Weishaupt
Browse files

[coupling-ff-pm] Add interface exercise

parent 2ca10629
No related branches found
No related tags found
1 merge request!7Feature/exercise coupling
Showing
with 2271 additions and 0 deletions
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
add_custom_target(test_exercises) add_custom_target(test_exercises)
add_subdirectory(exercise-basic) add_subdirectory(exercise-basic)
add_subdirectory(exercise-coupling-ff-pm)
add_subdirectory(exercise-runtimeparams) add_subdirectory(exercise-runtimeparams)
add_subdirectory(exercise-grids) add_subdirectory(exercise-grids)
add_subdirectory(exercise-properties) add_subdirectory(exercise-properties)
......
add_subdirectory(interface)
# Exercise #5 (DuMuX course)
The aim of this exercise is to get familiar with the set up of coupled free flow/porous medium flow problems.
## Problem set-up
The model domain consists of two non-overlapping subdomains.
Free flow is modeled in the upper subdomain, while the lower subdomain models a flow in a porous medium.
Both single-phase flow and two-phase flow will be considered in the porous domain.
![](../extradoc/exercise5_setup.png)
### 0. Getting familiar with the code
* Navigate to the directory `exercises/exercise-coupling-ff-pm`
There are three sub folders: `interface`, `models` and `turbulence`.
The problem-related files for this exercise are:
* Three __main files__ for the three sub-tasks :`ex_interface_coupling_ff-pm.cc`, `ex2_coupling_ff-pm.cc`, `ex2_coupling_ff-pm.cc`,
* Three __free flow problem files__: `ex_interface_ffproblem.hh`, `ex2_ffproblem.hh`, `ex3_ffproblem.hh`
* Three __porous medium flow problem files__: `ex_interface_pmproblem.hh`, `ex2_pmproblem.hh`, `ex3_pmproblem.hh`
* The __input files__: ...
* The __spatial parameters files__: `1pspatialparams.hh`, `2pspatialparams.hh`
In the main file, `TypeTags` for both submodels are defined. The same applies for types such as `GridManager`, `FVGridGeometry`, `Problem`, etc.. Since we use a monolithic coupling scheme, there is only one `Assembler` and one
`NewtonSolver`.
The problem files very much look like "regular", uncoupled ones with the exception that they hold a pointer to the `CouplingManager` which allows to evaluate the coupling conditions and to exchange information between the coupled models. The coupling conditions are realized technically in terms of boundary condition. For instance, in lines 178 and 179
in `ex_interface_ffproblem.hh`, `couplingNeumann` boundary conditions are set, which means that the free flow models evaluates the
mass and momentum fluxes coming from the porous domain and uses these values as boundary conditions at the interface.
Note the certain checks are performed when combining different models, e.g., the fluid system has to be the same for both domains.
We will use a staggered grid for the free flow and a cell-centered finite volume method for the porous medium.
Keep in mind that the staggered grid implementation distinguishes between face variables (velocity components) and
cell center variables (all other variables), therefore in some cases either the `stokesCellCenterIdx`
or the `stokesFaceIdx` is used respectively, while for the porous medium all variables can be accessed with `darcyIdx`.
The main part of the Stokes/Darcy coupling is implemented in the folder `dumux/multidomain/boundary/stokesdarcy`.
__Task__:
Take a closer look at the Stokes/Darcy coupling files and try to answer the following questions before moving to the next part of the exercise:
* Where are the elements at the coupling interface paired with their respective coupling partner elements of the other domain?
* Where are the coupling conditions implemented and evaluated?
* You will find four implementations of the `massCouplingCondition`. What are the differences between them?
* Which data is stored and updated regularly such that it is accessible from the respective other domain?
* How can we access volume variables like density and pressure from the respective other domain?
* ...
### 1. Changing the interface
In this part of the exercise, a simple coupled system consisting of a one-phase (1p) free flow and a one-phase flow in a porous medium is set up. Both subproblems have no-flow boundaries at the sides.
A velocity profile is set on the upper free flow boundary, which leads to a vertical flow into the porous medium.
* We will first change the flow direction such that the free flow is parallel to the porous medium.
* Afterwards, the Beavers-Joseph-Saffman condition will be used as an interface condition for the tangential momentum transfer.
* Last, we change the flat interface between the two domains to a wave-shaped one.
__Tasks__:
Open the file `ex_interface_ffproblem.hh` and navigate to line 155, where the types of boundary condition are set.
Instead of applying a fixed velocity profile at the top of the domain, we want to use fixed pressure boundary conditions
at the left and right side of the free flow domain, while the top represents an impermeable wall.
__Change the flow direction__
Set a Dirichlet boundary condition for the pressure at the left and ride side of the domain:
``` cpp
if(onLeftBoundary_(globalPos) || onRightBoundary_(globalPos))
values.setDirichlet(Indices::pressureIdx);
```
Set a Dirichlet boundary condition for the velocities at the top:
``` cpp
if(onUpperBoundary_(globalPos))
{
values.setDirichlet(Indices::velocityXIdx);
values.setDirichlet(Indices::velocityYIdx);
}
```
Keep the coupling boundary condition:
``` cpp
if(couplingManager().isCoupledEntity(CouplingManager::stokesIdx, scvf))
{
values.setCouplingNeumann(Indices::conti0EqIdx);
values.setCouplingNeumann(Indices::momentumYBalanceIdx);
}
```
Having changed the types of boundary conditions, we must now assign the correct values for them.
Set a no-slip, no-flow condition for the velocity at the top:
``` cpp
values[Indices::velocityXIdx] = 0.0;
values[Indices::velocityYIdx] = 0.0;
```
Apply a fixed pressure difference between the inlet and outlet, e.g.:
``` cpp
if(onLeftBoundary_(globalPos))
values[Indices::pressureIdx] = deltaP_;
if(onRightBoundary_(globalPos))
values[Indices::pressureIdx] = 0.0;
```
For changing the flow direction, the boundary conditions for the porous medium have to be changed as well.
Use Neumann no-flow boundaries everywhere, keep the coupling conditions.
``` cpp
values.setAllNeumann();
if (couplingManager().isCoupledEntity(CouplingManager::darcyIdx, scvf))
values.setAllCouplingNeumann();
```
__Include slip-condition__
This should make the flow go from left to right. However, we are still missing one important feature:
the Beavers-Joseph-Saffman slip condition at the interface:
$`\frac{\partial v_x}{\partial y} = \frac{\alpha}{\sqrt K} (v_x - q_{pm})\quad`$ at $`\quad y=0`$
with $`\quad q_{pm}=0`$.
The include this, we just set:
``` cpp
values.setBJS(Indices::momentumXBalanceIdx);
```
at the position where the coupling boundary conditions are set in `ex_interface_ffproblem.hh`.
To check if the simulation behaves as expected, we can compare the velocity profile $`v_x(y)`$ with the analytical solution provided by [Beavers and Joseph (1967)](https://doi.org/10.1017/S0022112067001375).
For doing so, we uncomment line 212
```cpp
stokesVtkWriter.addField(stokesProblem->getAnalyticalVelocityX(), "analyticalV_x");
```
in `ex_interface_coupling_ff-pm.cc`. After re-compiling and re-running the executable, we should be able to see also
the analytical solution of $`v_x`$ on the free flow domain. Play around with the grid resolution to see how that affects the velocity profile.
__Cange shape of interface__
Now we want to include a non-flat interface between the two domains. We use `dune-subgrid` to construct
two grids for the two domains from one common host grid. Comment out lines 93-103 in `ex_interface_coupling_ff-pm.cc` and comment lines 112-147 in the same file. This will instantiate a host grid and define two helper lambda functions that are used to choose elements from to host grid for the respective sub grid. In the given case,
the domain is split in two haves, separated by a sinusoidal interface.
```cpp
auto elementSelectorStokes = [&](const auto& element)
{
double interface = params.amplitude * std::sin(( element.geometry().center()[0] -params.offset) / params.scaling * 2.0 * M_PI) + params.baseline;
return element.geometry().center()[1] > interface;
};
auto elementSelectorDarcy = [&](const auto& element)
{
double interface = params.amplitude * std::sin(( element.geometry().center()[0] - params.offset) / params.scaling * 2.0 * M_PI) + params.baseline;
return element.geometry().center()[1] < interface;
};
```
Make sure to comment in line 30 in both problem files
```cpp
#include <dumux/io/grid/subgridgridcreator.hh>
```
and do the changes in the respective lines for the `Grid` property.
The problem should no compile and run. However, an error occurs due to the coupling conditions.
So far, we assumed a flat interface, therefore the normal momentum coupling condition
$`[\sigma \cdot \mathbf{n}]^{FF} = p^{PM}`$
was always set for a fixed $`\mathbf{n} = (0,1)^T`$. We need to account for the curvature of the interface and thus replace
```cpp
values.setCouplingNeumann(Indices::momentumYBalanceIdx);
```
with
```cpp
values.setCouplingNeumann(scvf.directionIndex());
```
The same if true for the BJS condition, however, here we need to consider the tangential direction:
```cpp
values.setCouplingNeumann(1 - scvf.directionIndex());
```
The final result should look something like this:
![](../extradoc/ex_ff-pm-wave-interface.png)
### 3. Change the models
1p2c/1p2c -->1p2c/2p2c
__Task__:
...
### 4. ...
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
// vi: set et ts=4 sw=4 sts=4:
/*****************************************************************************
* See the file COPYING for full copying permissions. *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
*****************************************************************************/
/*!
* \file
* \ingroup OnePTests
* \brief The spatial parameters class for the test problem using the 1p cc model
*/
#ifndef DUMUX_1P_TEST_SPATIALPARAMS_HH
#define DUMUX_1P_TEST_SPATIALPARAMS_HH
#include <dumux/material/spatialparams/fv1p.hh>
namespace Dumux
{
/*!
* \ingroup OnePModel
* \ingroup ImplicitTestProblems
*
* \brief The spatial parameters class for the test problem using the
* 1p cc model
*/
template<class TypeTag>
class OnePSpatialParams
: public FVSpatialParamsOneP<typename GET_PROP_TYPE(TypeTag, FVGridGeometry),
typename GET_PROP_TYPE(TypeTag, Scalar),
OnePSpatialParams<TypeTag>>
{
using FVGridGeometry = typename GET_PROP_TYPE(TypeTag, FVGridGeometry);
using Scalar = typename GET_PROP_TYPE(TypeTag, Scalar);
using Problem = typename GET_PROP_TYPE(TypeTag, Problem);
using GridView = typename GET_PROP_TYPE(TypeTag, GridView);
using ParentType = FVSpatialParamsOneP<FVGridGeometry, Scalar, OnePSpatialParams<TypeTag>>;
using Element = typename GridView::template Codim<0>::Entity;
using GlobalPosition = typename Element::Geometry::GlobalCoordinate;
public:
// export permeability type
using PermeabilityType = Scalar;
OnePSpatialParams(std::shared_ptr<const FVGridGeometry> fvGridGeometry)
: ParentType(fvGridGeometry)
{
permeability_ = getParam<Scalar>("Darcy.SpatialParams.Permeability");
alphaBJ_ = getParam<Scalar>("Darcy.SpatialParams.AlphaBeaversJoseph");
}
/*!
* \brief Function for defining the (intrinsic) permeability \f$[m^2]\f$.
*
* \param globalPos The global position
* \return the intrinsic permeability
*/
PermeabilityType permeabilityAtPos(const GlobalPosition& globalPos) const
{ return permeability_; }
/*! \brief Define the porosity in [-].
*
* \param globalPos The global position
*/
Scalar porosityAtPos(const GlobalPosition& globalPos) const
{ return 0.4; }
/*! \brief Define the Beavers-Joseph coefficient in [-].
*
* \param globalPos The global position
*/
Scalar beaversJosephCoeffAtPos(const GlobalPosition& globalPos) const
{ return alphaBJ_; }
private:
Scalar permeability_;
Scalar alphaBJ_;
};
} // end namespace
#endif
add_input_file_links()
# executables for ex_interface_coupling_ff-pm
dune_add_test(NAME ex_interface_coupling_ff-pm
SOURCES ex_interface_coupling_ff-pm.cc
CMD_ARGS ex_interface_coupling_ff-pm.input)
# add tutorial to the common target
add_dependencies(test_exercises ex_interface_coupling_ff-pm)
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
// vi: set et ts=4 sw=4 sts=4:
/*****************************************************************************
* See the file COPYING for full copying permissions. *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
*****************************************************************************/
/*!
* \file
*
* \brief A test problem for the coupled Stokes/Darcy problem (1p)
*/
#include <config.h>
#include <iostream>
#include <dune/common/parallel/mpihelper.hh>
#include <dune/istl/io.hh>
#include <dumux/common/properties.hh>
#include <dumux/common/parameters.hh>
#include <dumux/common/dumuxmessage.hh>
#include <dumux/linear/seqsolverbackend.hh>
#include <dumux/assembly/fvassembler.hh>
#include <dumux/assembly/diffmethod.hh>
#include <dumux/discretization/methods.hh>
#include <dumux/io/vtkoutputmodule.hh>
#include <dumux/io/staggeredvtkoutputmodule.hh>
#include <dumux/io/grid/gridmanager.hh>
#include <dumux/multidomain/staggeredtraits.hh>
#include <dumux/multidomain/fvassembler.hh>
#include <dumux/multidomain/newtonsolver.hh>
#include <dumux/multidomain/boundary/stokesdarcy/couplingmanager.hh>
#include "ex_interface_pmproblem.hh"
#include "ex_interface_ffproblem.hh"
namespace Dumux {
namespace Properties {
SET_PROP(StokesOnePTypeTag, CouplingManager)
{
using Traits = StaggeredMultiDomainTraits<TypeTag, TypeTag, TTAG(DarcyOnePTypeTag)>;
using type = Dumux::StokesDarcyCouplingManager<Traits>;
};
SET_PROP(DarcyOnePTypeTag, CouplingManager)
{
using Traits = StaggeredMultiDomainTraits<TTAG(StokesOnePTypeTag), TTAG(StokesOnePTypeTag), TypeTag>;
using type = Dumux::StokesDarcyCouplingManager<Traits>;
};
} // end namespace Properties
} // end namespace Dumux
int main(int argc, char** argv) try
{
using namespace Dumux;
// initialize MPI, finalize is done automatically on exit
const auto& mpiHelper = Dune::MPIHelper::instance(argc, argv);
// print dumux start message
if (mpiHelper.rank() == 0)
DumuxMessage::print(/*firstCall=*/true);
// parse command line arguments and input file
Parameters::init(argc, argv);
// Define the sub problem type tags
using StokesTypeTag = TTAG(StokesOnePTypeTag);
using DarcyTypeTag = TTAG(DarcyOnePTypeTag);
// ******************** comment-out this section for the last exercise **************** //
// create two individual grids (from the given grid file or the input file)
// for both sub-domains
using DarcyGridManager = Dumux::GridManager<typename GET_PROP_TYPE(DarcyTypeTag, Grid)>;
DarcyGridManager darcyGridManager;
darcyGridManager.init("Darcy"); // pass parameter group
using StokesGridManager = Dumux::GridManager<typename GET_PROP_TYPE(StokesTypeTag, Grid)>;
StokesGridManager stokesGridManager;
stokesGridManager.init("Stokes"); // pass parameter group
// we compute on the leaf grid view
const auto& darcyGridView = darcyGridManager.grid().leafGridView();
const auto& stokesGridView = stokesGridManager.grid().leafGridView();
// ************************************************************************************ //
// ******************** uncomment this section for the last exercise ****************** //
// // use dune-subgrid to create the individual grids
// static constexpr int dim = 2;
// using HostGrid = Dune::YaspGrid<2, Dune::TensorProductCoordinates<double, dim> >;
// using HostGridManager = Dumux::GridManager<HostGrid>;
// HostGridManager hostGridManager;
// hostGridManager.init();
// auto& hostGrid = hostGridManager.grid();
//
// struct Params
// {
// double amplitude = getParam<double>("Grid.Amplitude");
// double baseline = getParam<double>("Grid.Baseline");
// double offset = getParam<double>("Grid.Offset");
// double scaling = getParam<double>("Grid.Scaling");
// };
//
// Params params;
//
// auto elementSelectorStokes = [&](const auto& element)
// {
// double interface = params.amplitude * std::sin(( element.geometry().center()[0] -params.offset) / params.scaling * 2.0 * M_PI) + params.baseline;
// return element.geometry().center()[1] > interface;
// };
//
// auto elementSelectorDarcy = [&](const auto& element)
// {
// double interface = params.amplitude * std::sin(( element.geometry().center()[0] - params.offset) / params.scaling * 2.0 * M_PI) + params.baseline;
// return element.geometry().center()[1] < interface;
// };
//
// // subgrid Pointer
// auto stokesGridPtr = SubgridGridCreator<HostGrid>::makeGrid(hostGrid, elementSelectorStokes, "Stokes");
// auto darcyGridPtr = SubgridGridCreator<HostGrid>::makeGrid(hostGrid, elementSelectorDarcy, "Darcy");
//
// // we compute on the leaf grid view
// const auto& darcyGridView = darcyGridPtr->leafGridView();
// const auto& stokesGridView = stokesGridPtr->leafGridView();
// ************************************************************************************ //
// create the finite volume grid geometry
using StokesFVGridGeometry = typename GET_PROP_TYPE(StokesTypeTag, FVGridGeometry);
auto stokesFvGridGeometry = std::make_shared<StokesFVGridGeometry>(stokesGridView);
stokesFvGridGeometry->update();
using DarcyFVGridGeometry = typename GET_PROP_TYPE(DarcyTypeTag, FVGridGeometry);
auto darcyFvGridGeometry = std::make_shared<DarcyFVGridGeometry>(darcyGridView);
darcyFvGridGeometry->update();
using Traits = StaggeredMultiDomainTraits<StokesTypeTag, StokesTypeTag, DarcyTypeTag>;
// the coupling manager
using CouplingManager = StokesDarcyCouplingManager<Traits>;
auto couplingManager = std::make_shared<CouplingManager>(stokesFvGridGeometry, darcyFvGridGeometry);
// the indices
constexpr auto stokesCellCenterIdx = CouplingManager::stokesCellCenterIdx;
constexpr auto stokesFaceIdx = CouplingManager::stokesFaceIdx;
constexpr auto darcyIdx = CouplingManager::darcyIdx;
// the problem (initial and boundary conditions)
using StokesProblem = typename GET_PROP_TYPE(StokesTypeTag, Problem);
auto stokesProblem = std::make_shared<StokesProblem>(stokesFvGridGeometry, couplingManager);
using DarcyProblem = typename GET_PROP_TYPE(DarcyTypeTag, Problem);
auto darcyProblem = std::make_shared<DarcyProblem>(darcyFvGridGeometry, couplingManager);
// the solution vector
Traits::SolutionVector sol;
sol[stokesCellCenterIdx].resize(stokesFvGridGeometry->numCellCenterDofs());
sol[stokesFaceIdx].resize(stokesFvGridGeometry->numFaceDofs());
sol[darcyIdx].resize(darcyFvGridGeometry->numDofs());
const auto& cellCenterSol = sol[stokesCellCenterIdx];
const auto& faceSol = sol[stokesFaceIdx];
// apply initial solution for instationary problems
typename GET_PROP_TYPE(StokesTypeTag, SolutionVector) stokesSol;
std::get<0>(stokesSol) = cellCenterSol;
std::get<1>(stokesSol) = faceSol;
stokesProblem->applyInitialSolution(stokesSol);
sol[stokesCellCenterIdx] = stokesSol[stokesCellCenterIdx];
sol[stokesFaceIdx] = stokesSol[stokesFaceIdx];
couplingManager->init(stokesProblem, darcyProblem, sol);
// the grid variables
using StokesGridVariables = typename GET_PROP_TYPE(StokesTypeTag, GridVariables);
auto stokesGridVariables = std::make_shared<StokesGridVariables>(stokesProblem, stokesFvGridGeometry);
stokesGridVariables->init(stokesSol);
using DarcyGridVariables = typename GET_PROP_TYPE(DarcyTypeTag, GridVariables);
auto darcyGridVariables = std::make_shared<DarcyGridVariables>(darcyProblem, darcyFvGridGeometry);
darcyGridVariables->init(sol[darcyIdx]);
// intialize the vtk output module
const auto stokesName = getParam<std::string>("Problem.Name") + "_" + stokesProblem->name();
const auto darcyName = getParam<std::string>("Problem.Name") + "_" + darcyProblem->name();
StaggeredVtkOutputModule<StokesTypeTag> stokesVtkWriter(*stokesProblem, *stokesFvGridGeometry, *stokesGridVariables, stokesSol, stokesName);
GET_PROP_TYPE(StokesTypeTag, VtkOutputFields)::init(stokesVtkWriter);
//****** uncomment the add analytical solution of v_x *****//
// stokesVtkWriter.addField(stokesProblem->getAnalyticalVelocityX(), "analyticalV_x");
stokesVtkWriter.write(0.0);
VtkOutputModule<DarcyTypeTag> darcyVtkWriter(*darcyProblem, *darcyFvGridGeometry, *darcyGridVariables, sol[darcyIdx], darcyName);
GET_PROP_TYPE(DarcyTypeTag, VtkOutputFields)::init(darcyVtkWriter);
darcyVtkWriter.write(0.0);
// the assembler for a stationary problem
using Assembler = MultiDomainFVAssembler<Traits, CouplingManager, DiffMethod::numeric>;
auto assembler = std::make_shared<Assembler>(std::make_tuple(stokesProblem, stokesProblem, darcyProblem),
std::make_tuple(stokesFvGridGeometry->cellCenterFVGridGeometryPtr(),
stokesFvGridGeometry->faceFVGridGeometryPtr(),
darcyFvGridGeometry),
std::make_tuple(stokesGridVariables->cellCenterGridVariablesPtr(),
stokesGridVariables->faceGridVariablesPtr(),
darcyGridVariables),
couplingManager);
// the linear solver
using LinearSolver = UMFPackBackend;
auto linearSolver = std::make_shared<LinearSolver>();
// the non-linear solver
using NewtonSolver = MultiDomainNewtonSolver<Assembler, LinearSolver, CouplingManager>;
NewtonSolver nonLinearSolver(assembler, linearSolver, couplingManager);
// solve the non-linear system
nonLinearSolver.solve(sol);
// write vtk output
stokesVtkWriter.write(1.0);
darcyVtkWriter.write(1.0);
////////////////////////////////////////////////////////////
// finalize, print dumux message to say goodbye
////////////////////////////////////////////////////////////
// print dumux end message
if (mpiHelper.rank() == 0)
{
Parameters::print();
DumuxMessage::print(/*firstCall=*/false);
}
return 0;
} // end main
catch (Dumux::ParameterException &e)
{
std::cerr << std::endl << e << " ---> Abort!" << std::endl;
return 1;
}
catch (Dune::DGFException & e)
{
std::cerr << "DGF exception thrown (" << e <<
"). Most likely, the DGF file name is wrong "
"or the DGF file is corrupted, "
"e.g. missing hash at end of file or wrong number (dimensions) of entries."
<< " ---> Abort!" << std::endl;
return 2;
}
catch (Dune::Exception &e)
{
std::cerr << "Dune reported error: " << e << " ---> Abort!" << std::endl;
return 3;
}
catch (...)
{
std::cerr << "Unknown exception thrown! ---> Abort!" << std::endl;
return 4;
}
# for dune-subgrid
[Grid]
Positions0 = 0 1
Positions1 = 0 0.2 0.3 0.65
Cells0 = 100
Cells1 = 10 50 18
Baseline = 0.25 # [m]
Amplitude = 0.04 # [m]
Offset = 0.5 # [m]
Scaling = 0.2 #[m]
[Stokes.Grid]
Verbosity = true
Positions0 = 0.0 1.0
Positions1 = 1.0 2.0
Cells0 = 20
Cells1 = 100
Grading1 = 1
[Darcy.Grid]
Verbosity = true
Positions0 = 0.0 1.0
Positions1 = 0.0 1.0
Cells0 = 20
Cells1 = 20
Grading1 = 1
[Stokes.Problem]
Name = stokes
PressureDifference = 1e-9
[Darcy.Problem]
Name = darcy
[Darcy.SpatialParams]
Permeability = 1e-6 # m^2
AlphaBeaversJoseph = 1.0
[Problem]
Name = ex_ff-pm-interface
EnableGravity = false
[Vtk]
AddVelocity = 1
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
// vi: set et ts=4 sw=4 sts=4:
/*****************************************************************************
* See the file COPYING for full copying permissions. *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
*****************************************************************************/
/*!
* \file
* \brief The free flow sub problem
*/
#ifndef DUMUX_STOKES_SUBPROBLEM_HH
#define DUMUX_STOKES_SUBPROBLEM_HH
#include <dune/grid/yaspgrid.hh>
//****** uncomment for the last exercise *****//
// #include <dumux/io/grid/subgridgridcreator.hh>
#include <dumux/material/fluidsystems/1pliquid.hh>
#include <dumux/material/components/simpleh2o.hh>
#include <dumux/freeflow/navierstokes/problem.hh>
#include <dumux/discretization/staggered/freeflow/properties.hh>
#include <dumux/freeflow/navierstokes/model.hh>
namespace Dumux
{
template <class TypeTag>
class StokesSubProblem;
namespace Properties
{
NEW_TYPE_TAG(StokesOnePTypeTag, INHERITS_FROM(StaggeredFreeFlowModel, NavierStokes));
// the fluid system
SET_PROP(StokesOnePTypeTag, FluidSystem)
{
using Scalar = typename GET_PROP_TYPE(TypeTag, Scalar);
using type = FluidSystems::OnePLiquid<Scalar, Dumux::Components::SimpleH2O<Scalar> > ;
};
// Set the grid type
SET_PROP(StokesOnePTypeTag, Grid)
{
static constexpr auto dim = 2;
using Scalar = typename GET_PROP_TYPE(TypeTag, Scalar);
using TensorGrid = Dune::YaspGrid<2, Dune::TensorProductCoordinates<Scalar, dim> >;
//****** comment out for the last exercise *****//
using type = TensorGrid;
//****** uncomment for the last exercise *****//
// using HostGrid = TensorGrid;
// using type = Dune::SubGrid<dim, HostGrid>;
};
// Set the problem property
SET_TYPE_PROP(StokesOnePTypeTag, Problem, Dumux::StokesSubProblem<TypeTag> );
SET_BOOL_PROP(StokesOnePTypeTag, EnableFVGridGeometryCache, true);
SET_BOOL_PROP(StokesOnePTypeTag, EnableGridFluxVariablesCache, true);
SET_BOOL_PROP(StokesOnePTypeTag, EnableGridVolumeVariablesCache, true);
SET_BOOL_PROP(StokesOnePTypeTag, EnableInertiaTerms, false);
}
/*!
* \brief The free flow sub problem
*/
template <class TypeTag>
class StokesSubProblem : public NavierStokesProblem<TypeTag>
{
using ParentType = NavierStokesProblem<TypeTag>;
using GridView = typename GET_PROP_TYPE(TypeTag, GridView);
using Scalar = typename GET_PROP_TYPE(TypeTag, Scalar);
using Indices = typename GET_PROP_TYPE(TypeTag, ModelTraits)::Indices;
using BoundaryTypes = typename GET_PROP_TYPE(TypeTag, BoundaryTypes);
using FVGridGeometry = typename GET_PROP_TYPE(TypeTag, FVGridGeometry);
using FVElementGeometry = typename FVGridGeometry::LocalView;
using SubControlVolumeFace = typename FVElementGeometry::SubControlVolumeFace;
using Element = typename GridView::template Codim<0>::Entity;
using GlobalPosition = typename Element::Geometry::GlobalCoordinate;
using PrimaryVariables = typename GET_PROP_TYPE(TypeTag, PrimaryVariables);
using NumEqVector = typename GET_PROP_TYPE(TypeTag, NumEqVector);
using FluidSystem = typename GET_PROP_TYPE(TypeTag, FluidSystem);
using CouplingManager = typename GET_PROP_TYPE(TypeTag, CouplingManager);
public:
StokesSubProblem(std::shared_ptr<const FVGridGeometry> fvGridGeometry, std::shared_ptr<CouplingManager> couplingManager)
: ParentType(fvGridGeometry, "Stokes"), eps_(1e-6), couplingManager_(couplingManager)
{
deltaP_ = getParamFromGroup<Scalar>(this->paramGroup(), "Problem.PressureDifference");
}
/*!
* \name Problem parameters
*/
// \{
/*!
* \brief Return the temperature within the domain in [K].
*
* This problem assumes a temperature of 10 degrees Celsius.
*/
Scalar temperature() const
{ return 273.15 + 10; } // 10°C
/*!
* \brief Return the sources within the domain.
*
* \param globalPos The global position
*/
NumEqVector sourceAtPos(const GlobalPosition &globalPos) const
{ return NumEqVector(0.0); }
// \}
/*!
* \name Boundary conditions
*/
// \{
/*!
* \brief Specifies which kind of boundary condition should be
* used for which equation on a given boundary segment.
*
* \param element The finite element
* \param scvf The sub control volume face
*/
BoundaryTypes boundaryTypes(const Element& element,
const SubControlVolumeFace& scvf) const
{
BoundaryTypes values;
const auto& globalPos = scvf.dofPosition();
if(onUpperBoundary_(globalPos))
{
values.setDirichlet(Indices::velocityXIdx);
values.setDirichlet(Indices::velocityYIdx);
}
// left/right wall
if (onRightBoundary_(globalPos) || (onLeftBoundary_(globalPos)))
{
values.setDirichlet(Indices::velocityXIdx);
values.setDirichlet(Indices::velocityYIdx);
}
// coupling interface
if(couplingManager().isCoupledEntity(CouplingManager::stokesIdx, scvf))
{
values.setCouplingNeumann(Indices::conti0EqIdx);
values.setCouplingNeumann(Indices::momentumYBalanceIdx);
}
return values;
}
/*!
* \brief Evaluate the boundary conditions for a Dirichlet control volume.
*
* \param globalPos The global position
*/
PrimaryVariables dirichletAtPos(const GlobalPosition& globalPos) const
{
PrimaryVariables values(0.0);
values = initialAtPos(globalPos);
return values;
}
/*!
* \brief Evaluate the boundary conditions for a Neumann control volume.
*
* \param element The element for which the Neumann boundary condition is set
* \param fvGeomentry The fvGeometry
* \param elemVolVars The element volume variables
* \param elemFaceVars The element face variables
* \param scvf The boundary sub control volume face
*/
template<class ElementVolumeVariables, class ElementFaceVariables>
NumEqVector neumann(const Element& element,
const FVElementGeometry& fvGeometry,
const ElementVolumeVariables& elemVolVars,
const ElementFaceVariables& elemFaceVars,
const SubControlVolumeFace& scvf) const
{
NumEqVector values(0.0);
if(couplingManager().isCoupledEntity(CouplingManager::stokesIdx, scvf))
{
values[Indices::conti0EqIdx] = couplingManager().couplingData().massCouplingCondition(fvGeometry, elemVolVars, elemFaceVars, scvf);
values[Indices::momentumYBalanceIdx] = couplingManager().couplingData().momentumCouplingCondition(fvGeometry, elemVolVars, elemFaceVars, scvf);
}
return values;
}
// \}
//! Set the coupling manager
void setCouplingManager(std::shared_ptr<CouplingManager> cm)
{ couplingManager_ = cm; }
//! Get the coupling manager
const CouplingManager& couplingManager() const
{ return *couplingManager_; }
/*!
* \name Volume terms
*/
// \{
/*!
* \brief Evaluate the initial value for a control volume.
*
* \param globalPos The global position
*/
PrimaryVariables initialAtPos(const GlobalPosition &globalPos) const
{
PrimaryVariables values(0.0);
values[Indices::velocityYIdx] = -1e-6 * globalPos[0] * (this->fvGridGeometry().bBoxMax()[0] - globalPos[0]);
return values;
}
/*!
* \brief Returns the intrinsic permeability of required as input parameter for the Beavers-Joseph-Saffman boundary condition
*/
Scalar permeability(const SubControlVolumeFace& scvf) const
{
return couplingManager().couplingData().darcyPermeability(scvf);
}
/*!
* \brief Returns the alpha value required as input parameter for the Beavers-Joseph-Saffman boundary condition
*/
Scalar alphaBJ(const SubControlVolumeFace& scvf) const
{
return couplingManager().problem(CouplingManager::darcyIdx).spatialParams().beaversJosephCoeffAtPos(scvf.center());
}
/*!
* \brief calculate the analytical velocity in x direction based on Beavers & Joseph (1967)
*/
void calculateAnalyticalVelocityX() const
{
analyticalVelocityX_.resize(this->fvGridGeometry().gridView().size(0));
using std::sqrt;
const Scalar dPdX = -deltaP_ / (this->fvGridGeometry().bBoxMax()[0] - this->fvGridGeometry().bBoxMin()[0]);
static const Scalar mu = FluidSystem::viscosity(temperature(), 1e5);
static const Scalar alpha = getParam<Scalar>("Darcy.SpatialParams.AlphaBeaversJoseph");
static const Scalar K = getParam<Scalar>("Darcy.SpatialParams.Permeability");
static const Scalar sqrtK = sqrt(K);
const Scalar sigma = (this->fvGridGeometry().bBoxMax()[1] - this->fvGridGeometry().bBoxMin()[1])/sqrtK;
const Scalar uB = -K/(2.0*mu) * ((sigma*sigma + 2.0*alpha*sigma) / (1.0 + alpha*sigma)) * dPdX;
for (const auto& element : elements(this->fvGridGeometry().gridView()))
{
const auto eIdx = this->fvGridGeometry().gridView().indexSet().index(element);
const Scalar y = element.geometry().center()[1] - this->fvGridGeometry().bBoxMin()[1];
const Scalar u = uB*(1.0 + alpha/sqrtK*y) + 1.0/(2.0*mu) * (y*y + 2*alpha*y*sqrtK) * dPdX;
analyticalVelocityX_[eIdx] = u;
}
}
/*!
* \brief Get the analytical velocity in x direction
*/
const std::vector<Scalar>& getAnalyticalVelocityX() const
{
if(analyticalVelocityX_.empty())
calculateAnalyticalVelocityX();
return analyticalVelocityX_;
}
// \}
private:
bool onLeftBoundary_(const GlobalPosition &globalPos) const
{ return globalPos[0] < this->fvGridGeometry().bBoxMin()[0] + eps_; }
bool onRightBoundary_(const GlobalPosition &globalPos) const
{ return globalPos[0] > this->fvGridGeometry().bBoxMax()[0] - eps_; }
bool onLowerBoundary_(const GlobalPosition &globalPos) const
{ return globalPos[1] < this->fvGridGeometry().bBoxMin()[1] + eps_; }
bool onUpperBoundary_(const GlobalPosition &globalPos) const
{ return globalPos[1] > this->fvGridGeometry().bBoxMax()[1] - eps_; }
Scalar eps_;
Scalar deltaP_;
std::shared_ptr<CouplingManager> couplingManager_;
mutable std::vector<Scalar> analyticalVelocityX_;
};
} //end namespace
#endif // DUMUX_STOKES_SUBPROBLEM_HH
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
// vi: set et ts=4 sw=4 sts=4:
/*****************************************************************************
* See the file COPYING for full copying permissions. *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
*****************************************************************************/
/*!
* \file
*
* \brief The porous medium flow sub problem
*/
#ifndef DUMUX_DARCY_SUBPROBLEM_HH
#define DUMUX_DARCY_SUBPROBLEM_HH
#include <dune/grid/yaspgrid.hh>
//****** uncomment for the last exercise *****//
// #include <dumux/io/grid/subgridgridcreator.hh>
#include <dumux/discretization/cellcentered/tpfa/properties.hh>
#include <dumux/porousmediumflow/1p/model.hh>
#include <dumux/porousmediumflow/problem.hh>
#include "1pspatialparams.hh"
#include <dumux/material/components/simpleh2o.hh>
#include <dumux/material/fluidsystems/1pliquid.hh>
namespace Dumux
{
template <class TypeTag>
class DarcySubProblem;
namespace Properties
{
NEW_TYPE_TAG(DarcyOnePTypeTag, INHERITS_FROM(CCTpfaModel, OneP));
// Set the problem property
SET_TYPE_PROP(DarcyOnePTypeTag, Problem, Dumux::DarcySubProblem<TypeTag>);
// the fluid system
SET_PROP(DarcyOnePTypeTag, FluidSystem)
{
using Scalar = typename GET_PROP_TYPE(TypeTag, Scalar);
using type = FluidSystems::OnePLiquid<Scalar, Dumux::Components::SimpleH2O<Scalar> > ;
};
// Set the grid type
SET_PROP(DarcyOnePTypeTag, Grid)
{
static constexpr auto dim = 2;
using Scalar = typename GET_PROP_TYPE(TypeTag, Scalar);
using TensorGrid = Dune::YaspGrid<2, Dune::TensorProductCoordinates<Scalar, dim> >;
//****** comment out for the last exercise *****//
using type = TensorGrid;
//****** uncomment for the last exercise *****//
// using HostGrid = TensorGrid;
// using type = Dune::SubGrid<dim, HostGrid>;
};
SET_TYPE_PROP(DarcyOnePTypeTag, SpatialParams, OnePSpatialParams<TypeTag>);
}
/*!
* \brief The porous medium flow sub problem
*/
template <class TypeTag>
class DarcySubProblem : public PorousMediumFlowProblem<TypeTag>
{
using ParentType = PorousMediumFlowProblem<TypeTag>;
using GridView = typename GET_PROP_TYPE(TypeTag, GridView);
using Scalar = typename GET_PROP_TYPE(TypeTag, Scalar);
using PrimaryVariables = typename GET_PROP_TYPE(TypeTag, PrimaryVariables);
using NumEqVector = typename GET_PROP_TYPE(TypeTag, NumEqVector);
using BoundaryTypes = typename GET_PROP_TYPE(TypeTag, BoundaryTypes);
using VolumeVariables = typename GET_PROP_TYPE(TypeTag, VolumeVariables);
using FVElementGeometry = typename GET_PROP_TYPE(TypeTag, FVGridGeometry)::LocalView;
using SubControlVolume = typename FVElementGeometry::SubControlVolume;
using SubControlVolumeFace = typename FVElementGeometry::SubControlVolumeFace;
using FVGridGeometry = typename GET_PROP_TYPE(TypeTag, FVGridGeometry);
using Indices = typename GET_PROP_TYPE(TypeTag, ModelTraits)::Indices;
using Element = typename GridView::template Codim<0>::Entity;
using GlobalPosition = typename Element::Geometry::GlobalCoordinate;
using CouplingManager = typename GET_PROP_TYPE(TypeTag, CouplingManager);
public:
DarcySubProblem(std::shared_ptr<const FVGridGeometry> fvGridGeometry,
std::shared_ptr<CouplingManager> couplingManager)
: ParentType(fvGridGeometry, "Darcy"), eps_(1e-7), couplingManager_(couplingManager)
{}
/*!
* \name Simulation steering
*/
// \{
/*!
* \brief Return the temperature within the domain in [K].
*
*/
Scalar temperature() const
{ return 273.15 + 10; } // 10°C
// \}
/*!
* \name Boundary conditions
*/
// \{
/*!
* \brief Specifies which kind of boundary condition should be
* used for which equation on a given boundary control volume.
*
* \param element The element
* \param scvf The boundary sub control volume face
*/
BoundaryTypes boundaryTypes(const Element &element, const SubControlVolumeFace &scvf) const
{
BoundaryTypes values;
values.setAllNeumann();
if (onLowerBoundary_(scvf.center()))
values.setAllDirichlet();
return values;
}
/*!
* \brief Evaluate the boundary conditions for a Dirichlet control volume.
*
* \param element The element for which the Dirichlet boundary condition is set
* \param scvf The boundary subcontrolvolumeface
*
* For this method, the \a values parameter stores primary variables.
*/
PrimaryVariables dirichlet(const Element &element, const SubControlVolumeFace &scvf) const
{
PrimaryVariables values(0.0);
values = initial(element);
return values;
}
/*!
* \brief Evaluate the boundary conditions for a Neumann control volume.
*
* \param element The element for which the Neumann boundary condition is set
* \param fvGeomentry The fvGeometry
* \param elemVolVars The element volume variables
* \param scvf The boundary sub control volume face
*
* For this method, the \a values variable stores primary variables.
*/
template<class ElementVolumeVariables>
NumEqVector neumann(const Element& element,
const FVElementGeometry& fvGeometry,
const ElementVolumeVariables& elemVolVars,
const SubControlVolumeFace& scvf) const
{
NumEqVector values(0.0);
if (couplingManager().isCoupledEntity(CouplingManager::darcyIdx, scvf))
values[Indices::conti0EqIdx] = couplingManager().couplingData().massCouplingCondition(fvGeometry, elemVolVars, scvf);
return values;
}
// \}
/*!
* \name Volume terms
*/
// \{
/*!
* \brief Evaluate the source term for all phases within a given
* sub-control-volume.
*
* \param element The element for which the source term is set
* \param fvGeomentry The fvGeometry
* \param elemVolVars The element volume variables
* \param scv The subcontrolvolume
*/
template<class ElementVolumeVariables>
NumEqVector source(const Element &element,
const FVElementGeometry& fvGeometry,
const ElementVolumeVariables& elemVolVars,
const SubControlVolume &scv) const
{ return NumEqVector(0.0); }
// \}
/*!
* \brief Evaluate the initial value for a control volume.
*
* \param element The element
*
* For this method, the \a priVars parameter stores primary
* variables.
*/
PrimaryVariables initial(const Element &element) const
{
return PrimaryVariables(0.0);
}
// \}
//! Set the coupling manager
void setCouplingManager(std::shared_ptr<CouplingManager> cm)
{ couplingManager_ = cm; }
//! Get the coupling manager
const CouplingManager& couplingManager() const
{ return *couplingManager_; }
private:
bool onLeftBoundary_(const GlobalPosition &globalPos) const
{ return globalPos[0] < this->fvGridGeometry().bBoxMin()[0] + eps_; }
bool onRightBoundary_(const GlobalPosition &globalPos) const
{ return globalPos[0] > this->fvGridGeometry().bBoxMax()[0] - eps_; }
bool onLowerBoundary_(const GlobalPosition &globalPos) const
{ return globalPos[1] < this->fvGridGeometry().bBoxMin()[1] + eps_; }
bool onUpperBoundary_(const GlobalPosition &globalPos) const
{ return globalPos[1] > this->fvGridGeometry().bBoxMax()[1] - eps_; }
Scalar eps_;
std::shared_ptr<CouplingManager> couplingManager_;
};
} //end namespace
#endif //DUMUX_DARCY_SUBPROBLEM_HH
exercises/extradoc/ex_ff-pm-vertical-flow.png

46.4 KiB

exercises/extradoc/ex_ff-pm-wave-interface.png

87.8 KiB

add_subdirectory(exercise-basic) add_subdirectory(exercise-basic)
add_subdirectory(exercise-coupling-ff-pm)
add_subdirectory(exercise-fluidsystem) add_subdirectory(exercise-fluidsystem)
add_subdirectory(exercise-grids) add_subdirectory(exercise-grids)
add_subdirectory(exercise-mainfile) add_subdirectory(exercise-mainfile)
......
add_subdirectory(interface)
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
// vi: set et ts=4 sw=4 sts=4:
/*****************************************************************************
* See the file COPYING for full copying permissions. *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
*****************************************************************************/
/*!
* \file
* \ingroup OnePTests
* \brief The spatial parameters class for the test problem using the 1p cc model
*/
#ifndef DUMUX_1P_TEST_SPATIALPARAMS_HH
#define DUMUX_1P_TEST_SPATIALPARAMS_HH
#include <dumux/material/spatialparams/fv1p.hh>
namespace Dumux
{
/*!
* \ingroup OnePModel
* \ingroup ImplicitTestProblems
*
* \brief The spatial parameters class for the test problem using the
* 1p cc model
*/
template<class TypeTag>
class OnePSpatialParams
: public FVSpatialParamsOneP<typename GET_PROP_TYPE(TypeTag, FVGridGeometry),
typename GET_PROP_TYPE(TypeTag, Scalar),
OnePSpatialParams<TypeTag>>
{
using FVGridGeometry = typename GET_PROP_TYPE(TypeTag, FVGridGeometry);
using Scalar = typename GET_PROP_TYPE(TypeTag, Scalar);
using Problem = typename GET_PROP_TYPE(TypeTag, Problem);
using GridView = typename GET_PROP_TYPE(TypeTag, GridView);
using ParentType = FVSpatialParamsOneP<FVGridGeometry, Scalar, OnePSpatialParams<TypeTag>>;
using Element = typename GridView::template Codim<0>::Entity;
using GlobalPosition = typename Element::Geometry::GlobalCoordinate;
public:
// export permeability type
using PermeabilityType = Scalar;
OnePSpatialParams(std::shared_ptr<const FVGridGeometry> fvGridGeometry)
: ParentType(fvGridGeometry)
{
permeability_ = getParam<Scalar>("Darcy.SpatialParams.Permeability");
alphaBJ_ = getParam<Scalar>("Darcy.SpatialParams.AlphaBeaversJoseph");
}
/*!
* \brief Function for defining the (intrinsic) permeability \f$[m^2]\f$.
*
* \param globalPos The global position
* \return the intrinsic permeability
*/
PermeabilityType permeabilityAtPos(const GlobalPosition& globalPos) const
{ return permeability_; }
/*! \brief Define the porosity in [-].
*
* \param globalPos The global position
*/
Scalar porosityAtPos(const GlobalPosition& globalPos) const
{ return 0.4; }
/*! \brief Define the Beavers-Joseph coefficient in [-].
*
* \param globalPos The global position
*/
Scalar beaversJosephCoeffAtPos(const GlobalPosition& globalPos) const
{ return alphaBJ_; }
private:
Scalar permeability_;
Scalar alphaBJ_;
};
} // end namespace
#endif
add_input_file_links()
dune_add_test(NAME orig_ex_interface_coupling_ff-pm
SOURCES ex_interface_coupling_ff-pm.cc
COMPILE_DEFINITIONS EXNUMBER=0
CMD_ARGS ex_interface_coupling_ff-pm.input)
dune_add_test(NAME sol_a_ex_interface_coupling_ff-pm
SOURCES ex_interface_coupling_ff-pm.cc
COMPILE_DEFINITIONS EXNUMBER=1
CMD_ARGS ex_interface_coupling_ff-pm.input)
dune_add_test(NAME sol_b_ex_interface_coupling_ff-pm
SOURCES ex_interface_coupling_ff-pm.cc
COMPILE_DEFINITIONS EXNUMBER=2
CMD_ARGS ex_interface_coupling_ff-pm.input)
dune_add_test(NAME sol_c_ex_interface_coupling_ff-pm
SOURCES ex_interface_coupling_ff-pm.cc
COMPILE_DEFINITIONS EXNUMBER=3
CMD_ARGS ex_interface_coupling_ff-pm.input)
# add exercise to the common target
add_dependencies(test_exercises sol_a_ex_interface_coupling_ff-pm sol_b_ex_interface_coupling_ff-pm sol_b_ex_interface_coupling_ff-pm)
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
// vi: set et ts=4 sw=4 sts=4:
/*****************************************************************************
* See the file COPYING for full copying permissions. *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
*****************************************************************************/
/*!
* \file
*
* \brief A test problem for the coupled Stokes/Darcy problem (1p)
*/
#include <config.h>
#include <iostream>
#include <dune/common/parallel/mpihelper.hh>
#include <dune/istl/io.hh>
#include <dumux/common/properties.hh>
#include <dumux/common/parameters.hh>
#include <dumux/common/dumuxmessage.hh>
#include <dumux/linear/seqsolverbackend.hh>
#include <dumux/assembly/fvassembler.hh>
#include <dumux/assembly/diffmethod.hh>
#include <dumux/discretization/methods.hh>
#include <dumux/io/vtkoutputmodule.hh>
#include <dumux/io/staggeredvtkoutputmodule.hh>
#include <dumux/io/grid/gridmanager.hh>
#include <dumux/multidomain/staggeredtraits.hh>
#include <dumux/multidomain/fvassembler.hh>
#include <dumux/multidomain/newtonsolver.hh>
#include <dumux/multidomain/boundary/stokesdarcy/couplingmanager.hh>
#include "ex_interface_pmproblem.hh"
#include "ex_interface_ffproblem.hh"
namespace Dumux {
namespace Properties {
SET_PROP(StokesOnePTypeTag, CouplingManager)
{
using Traits = StaggeredMultiDomainTraits<TypeTag, TypeTag, TTAG(DarcyOnePTypeTag)>;
using type = Dumux::StokesDarcyCouplingManager<Traits>;
};
SET_PROP(DarcyOnePTypeTag, CouplingManager)
{
using Traits = StaggeredMultiDomainTraits<TTAG(StokesOnePTypeTag), TTAG(StokesOnePTypeTag), TypeTag>;
using type = Dumux::StokesDarcyCouplingManager<Traits>;
};
} // end namespace Properties
} // end namespace Dumux
int main(int argc, char** argv) try
{
using namespace Dumux;
// initialize MPI, finalize is done automatically on exit
const auto& mpiHelper = Dune::MPIHelper::instance(argc, argv);
// print dumux start message
if (mpiHelper.rank() == 0)
DumuxMessage::print(/*firstCall=*/true);
// parse command line arguments and input file
Parameters::init(argc, argv);
// Define the sub problem type tags
using StokesTypeTag = TTAG(StokesOnePTypeTag);
using DarcyTypeTag = TTAG(DarcyOnePTypeTag);
#if EXNUMBER < 3
// try to create a grid (from the given grid file or the input file)
// for both sub-domains
using DarcyGridManager = Dumux::GridManager<typename GET_PROP_TYPE(DarcyTypeTag, Grid)>;
DarcyGridManager darcyGridManager;
darcyGridManager.init("Darcy"); // pass parameter group
using StokesGridManager = Dumux::GridManager<typename GET_PROP_TYPE(StokesTypeTag, Grid)>;
StokesGridManager stokesGridManager;
stokesGridManager.init("Stokes"); // pass parameter group
// we compute on the leaf grid view
const auto& darcyGridView = darcyGridManager.grid().leafGridView();
const auto& stokesGridView = stokesGridManager.grid().leafGridView();
#else
// use dune-subgrid to create the individual grids
static constexpr int dim = 2;
using HostGrid = Dune::YaspGrid<2, Dune::TensorProductCoordinates<double, dim> >;
using HostGridManager = Dumux::GridManager<HostGrid>;
HostGridManager hostGridManager;
hostGridManager.init();
auto& hostGrid = hostGridManager.grid();
struct Params
{
double amplitude = getParam<double>("Grid.Amplitude");
double baseline = getParam<double>("Grid.Baseline");
double offset = getParam<double>("Grid.Offset");
double scaling = getParam<double>("Grid.Scaling");
};
Params params;
auto elementSelectorStokes = [&](const auto& element)
{
double interface = params.amplitude * std::sin(( element.geometry().center()[0] -params.offset) / params.scaling * 2.0 * M_PI) + params.baseline;
return element.geometry().center()[1] > interface;
};
auto elementSelectorDarcy = [&](const auto& element)
{
double interface = params.amplitude * std::sin(( element.geometry().center()[0] - params.offset) / params.scaling * 2.0 * M_PI) + params.baseline;
return element.geometry().center()[1] < interface;
};
// subgrid Pointer
auto stokesGridPtr = SubgridGridCreator<HostGrid>::makeGrid(hostGrid, elementSelectorStokes, "Stokes");
auto darcyGridPtr = SubgridGridCreator<HostGrid>::makeGrid(hostGrid, elementSelectorDarcy, "Darcy");
// we compute on the leaf grid view
const auto& darcyGridView = darcyGridPtr->leafGridView();
const auto& stokesGridView = stokesGridPtr->leafGridView();
#endif
// create the finite volume grid geometry
using StokesFVGridGeometry = typename GET_PROP_TYPE(StokesTypeTag, FVGridGeometry);
auto stokesFvGridGeometry = std::make_shared<StokesFVGridGeometry>(stokesGridView);
stokesFvGridGeometry->update();
using DarcyFVGridGeometry = typename GET_PROP_TYPE(DarcyTypeTag, FVGridGeometry);
auto darcyFvGridGeometry = std::make_shared<DarcyFVGridGeometry>(darcyGridView);
darcyFvGridGeometry->update();
using Traits = StaggeredMultiDomainTraits<StokesTypeTag, StokesTypeTag, DarcyTypeTag>;
// the coupling manager
using CouplingManager = StokesDarcyCouplingManager<Traits>;
auto couplingManager = std::make_shared<CouplingManager>(stokesFvGridGeometry, darcyFvGridGeometry);
// the indices
constexpr auto stokesCellCenterIdx = CouplingManager::stokesCellCenterIdx;
constexpr auto stokesFaceIdx = CouplingManager::stokesFaceIdx;
constexpr auto darcyIdx = CouplingManager::darcyIdx;
// the problem (initial and boundary conditions)
using StokesProblem = typename GET_PROP_TYPE(StokesTypeTag, Problem);
auto stokesProblem = std::make_shared<StokesProblem>(stokesFvGridGeometry, couplingManager);
using DarcyProblem = typename GET_PROP_TYPE(DarcyTypeTag, Problem);
auto darcyProblem = std::make_shared<DarcyProblem>(darcyFvGridGeometry, couplingManager);
// the solution vector
Traits::SolutionVector sol;
sol[stokesCellCenterIdx].resize(stokesFvGridGeometry->numCellCenterDofs());
sol[stokesFaceIdx].resize(stokesFvGridGeometry->numFaceDofs());
sol[darcyIdx].resize(darcyFvGridGeometry->numDofs());
const auto& cellCenterSol = sol[stokesCellCenterIdx];
const auto& faceSol = sol[stokesFaceIdx];
// apply initial solution for instationary problems
typename GET_PROP_TYPE(StokesTypeTag, SolutionVector) stokesSol;
std::get<0>(stokesSol) = cellCenterSol;
std::get<1>(stokesSol) = faceSol;
stokesProblem->applyInitialSolution(stokesSol);
sol[stokesCellCenterIdx] = stokesSol[stokesCellCenterIdx];
sol[stokesFaceIdx] = stokesSol[stokesFaceIdx];
couplingManager->init(stokesProblem, darcyProblem, sol);
// the grid variables
using StokesGridVariables = typename GET_PROP_TYPE(StokesTypeTag, GridVariables);
auto stokesGridVariables = std::make_shared<StokesGridVariables>(stokesProblem, stokesFvGridGeometry);
stokesGridVariables->init(stokesSol);
using DarcyGridVariables = typename GET_PROP_TYPE(DarcyTypeTag, GridVariables);
auto darcyGridVariables = std::make_shared<DarcyGridVariables>(darcyProblem, darcyFvGridGeometry);
darcyGridVariables->init(sol[darcyIdx]);
// intialize the vtk output module
const auto stokesName = getParam<std::string>("Problem.Name") + "_" + stokesProblem->name();
const auto darcyName = getParam<std::string>("Problem.Name") + "_" + darcyProblem->name();
StaggeredVtkOutputModule<StokesTypeTag> stokesVtkWriter(*stokesProblem, *stokesFvGridGeometry, *stokesGridVariables, stokesSol, stokesName);
GET_PROP_TYPE(StokesTypeTag, VtkOutputFields)::init(stokesVtkWriter);
#if EXNUMBER >= 2
stokesVtkWriter.addField(stokesProblem->getAnalyticalVelocityX(), "analyticalV_x");
#endif
stokesVtkWriter.write(0.0);
VtkOutputModule<DarcyTypeTag> darcyVtkWriter(*darcyProblem, *darcyFvGridGeometry, *darcyGridVariables, sol[darcyIdx], darcyName);
GET_PROP_TYPE(DarcyTypeTag, VtkOutputFields)::init(darcyVtkWriter);
darcyVtkWriter.write(0.0);
// the assembler for a stationary problem
using Assembler = MultiDomainFVAssembler<Traits, CouplingManager, DiffMethod::numeric>;
auto assembler = std::make_shared<Assembler>(std::make_tuple(stokesProblem, stokesProblem, darcyProblem),
std::make_tuple(stokesFvGridGeometry->cellCenterFVGridGeometryPtr(),
stokesFvGridGeometry->faceFVGridGeometryPtr(),
darcyFvGridGeometry),
std::make_tuple(stokesGridVariables->cellCenterGridVariablesPtr(),
stokesGridVariables->faceGridVariablesPtr(),
darcyGridVariables),
couplingManager);
// the linear solver
using LinearSolver = UMFPackBackend;
auto linearSolver = std::make_shared<LinearSolver>();
// the non-linear solver
using NewtonSolver = MultiDomainNewtonSolver<Assembler, LinearSolver, CouplingManager>;
NewtonSolver nonLinearSolver(assembler, linearSolver, couplingManager);
// solve the non-linear system
nonLinearSolver.solve(sol);
// write vtk output
stokesVtkWriter.write(1.0);
darcyVtkWriter.write(1.0);
////////////////////////////////////////////////////////////
// finalize, print dumux message to say goodbye
////////////////////////////////////////////////////////////
// print dumux end message
if (mpiHelper.rank() == 0)
{
Parameters::print();
DumuxMessage::print(/*firstCall=*/false);
}
return 0;
} // end main
catch (Dumux::ParameterException &e)
{
std::cerr << std::endl << e << " ---> Abort!" << std::endl;
return 1;
}
catch (Dune::DGFException & e)
{
std::cerr << "DGF exception thrown (" << e <<
"). Most likely, the DGF file name is wrong "
"or the DGF file is corrupted, "
"e.g. missing hash at end of file or wrong number (dimensions) of entries."
<< " ---> Abort!" << std::endl;
return 2;
}
catch (Dune::Exception &e)
{
std::cerr << "Dune reported error: " << e << " ---> Abort!" << std::endl;
return 3;
}
catch (...)
{
std::cerr << "Unknown exception thrown! ---> Abort!" << std::endl;
return 4;
}
# for dune-subgrid
[Grid]
Positions0 = 0 1
Positions1 = 0 0.2 0.3 0.65
Cells0 = 100
Cells1 = 10 50 18
Baseline = 0.25 # [m]
Amplitude = 0.04 # [m]
Offset = 0.5 # [m]
Scaling = 0.2 #[m]
[Stokes.Grid]
Verbosity = true
Positions0 = 0.0 1.0
Positions1 = 1.0 2.0
Cells0 = 20
Cells1 = 100
Grading1 = 1
[Darcy.Grid]
Verbosity = true
Positions0 = 0.0 1.0
Positions1 = 0.0 1.0
Cells0 = 20
Cells1 = 20
Grading1 = 1
[Stokes.Problem]
Name = stokes
PressureDifference = 1e-9
[Darcy.Problem]
Name = darcy
[Darcy.SpatialParams]
Permeability = 1e-6 # m^2
AlphaBeaversJoseph = 1.0
[Problem]
Name = ex_ff-pm-interface
EnableGravity = false
[Vtk]
AddVelocity = 1
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
// vi: set et ts=4 sw=4 sts=4:
/*****************************************************************************
* See the file COPYING for full copying permissions. *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
*****************************************************************************/
/*!
* \file
* \brief The free flow sub problem
*/
#ifndef DUMUX_STOKES_SUBPROBLEM_HH
#define DUMUX_STOKES_SUBPROBLEM_HH
#include <dune/grid/yaspgrid.hh>
#if EXNUMBER >= 3
#include <dumux/io/grid/subgridgridcreator.hh>
#endif
#include <dumux/material/fluidsystems/1pliquid.hh>
#include <dumux/material/components/simpleh2o.hh>
#include <dumux/freeflow/navierstokes/problem.hh>
#include <dumux/discretization/staggered/freeflow/properties.hh>
#include <dumux/freeflow/navierstokes/model.hh>
namespace Dumux
{
template <class TypeTag>
class StokesSubProblem;
namespace Properties
{
NEW_TYPE_TAG(StokesOnePTypeTag, INHERITS_FROM(StaggeredFreeFlowModel, NavierStokes));
// the fluid system
SET_PROP(StokesOnePTypeTag, FluidSystem)
{
using Scalar = typename GET_PROP_TYPE(TypeTag, Scalar);
using type = FluidSystems::OnePLiquid<Scalar, Dumux::Components::SimpleH2O<Scalar> > ;
};
// Set the grid type
SET_PROP(StokesOnePTypeTag, Grid)
{
static constexpr auto dim = 2;
using Scalar = typename GET_PROP_TYPE(TypeTag, Scalar);
using TensorGrid = Dune::YaspGrid<2, Dune::TensorProductCoordinates<Scalar, dim> >;
#if EXNUMBER < 3 // use "normal" grid
using type = TensorGrid;
#else // use dune-subgrid
using HostGrid = TensorGrid;
using type = Dune::SubGrid<dim, HostGrid>;
#endif
};
// Set the problem property
SET_TYPE_PROP(StokesOnePTypeTag, Problem, Dumux::StokesSubProblem<TypeTag> );
SET_BOOL_PROP(StokesOnePTypeTag, EnableFVGridGeometryCache, true);
SET_BOOL_PROP(StokesOnePTypeTag, EnableGridFluxVariablesCache, true);
SET_BOOL_PROP(StokesOnePTypeTag, EnableGridVolumeVariablesCache, true);
SET_BOOL_PROP(StokesOnePTypeTag, EnableInertiaTerms, false);
}
/*!
* \brief The free flow sub problem
*/
template <class TypeTag>
class StokesSubProblem : public NavierStokesProblem<TypeTag>
{
using ParentType = NavierStokesProblem<TypeTag>;
using GridView = typename GET_PROP_TYPE(TypeTag, GridView);
using Scalar = typename GET_PROP_TYPE(TypeTag, Scalar);
using Indices = typename GET_PROP_TYPE(TypeTag, ModelTraits)::Indices;
using BoundaryTypes = typename GET_PROP_TYPE(TypeTag, BoundaryTypes);
using FVGridGeometry = typename GET_PROP_TYPE(TypeTag, FVGridGeometry);
using FVElementGeometry = typename FVGridGeometry::LocalView;
using SubControlVolumeFace = typename FVElementGeometry::SubControlVolumeFace;
using Element = typename GridView::template Codim<0>::Entity;
using GlobalPosition = typename Element::Geometry::GlobalCoordinate;
using PrimaryVariables = typename GET_PROP_TYPE(TypeTag, PrimaryVariables);
using NumEqVector = typename GET_PROP_TYPE(TypeTag, NumEqVector);
using FluidSystem = typename GET_PROP_TYPE(TypeTag, FluidSystem);
using CouplingManager = typename GET_PROP_TYPE(TypeTag, CouplingManager);
public:
StokesSubProblem(std::shared_ptr<const FVGridGeometry> fvGridGeometry, std::shared_ptr<CouplingManager> couplingManager)
: ParentType(fvGridGeometry, "Stokes"), eps_(1e-6), couplingManager_(couplingManager)
{
deltaP_ = getParamFromGroup<Scalar>(this->paramGroup(), "Problem.PressureDifference");
}
/*!
* \name Problem parameters
*/
// \{
/*!
* \brief Return the temperature within the domain in [K].
*
* This problem assumes a temperature of 10 degrees Celsius.
*/
Scalar temperature() const
{ return 273.15 + 10; } // 10°C
/*!
* \brief Return the sources within the domain.
*
* \param globalPos The global position
*/
NumEqVector sourceAtPos(const GlobalPosition &globalPos) const
{ return NumEqVector(0.0); }
// \}
/*!
* \name Boundary conditions
*/
// \{
/*!
* \brief Specifies which kind of boundary condition should be
* used for which equation on a given boundary segment.
*
* \param element The finite element
* \param scvf The sub control volume face
*/
BoundaryTypes boundaryTypes(const Element& element,
const SubControlVolumeFace& scvf) const
{
BoundaryTypes values;
const auto& globalPos = scvf.dofPosition();
#if EXNUMBER == 0 // flow from top to bottom
if(onUpperBoundary_(globalPos))
{
values.setDirichlet(Indices::velocityXIdx);
values.setDirichlet(Indices::velocityYIdx);
}
if (onRightBoundary_(globalPos) || (onLeftBoundary_(globalPos)))
{
values.setDirichlet(Indices::velocityXIdx);
values.setDirichlet(Indices::velocityYIdx);
}
#else // flow flom left to right
if(onLeftBoundary_(globalPos) || onRightBoundary_(globalPos))
values.setDirichlet(Indices::pressureIdx);
else
{
values.setDirichlet(Indices::velocityXIdx);
values.setDirichlet(Indices::velocityYIdx);
}
#endif
if(couplingManager().isCoupledEntity(CouplingManager::stokesIdx, scvf))
{
values.setCouplingNeumann(Indices::conti0EqIdx);
#if EXNUMBER < 3
values.setCouplingNeumann(Indices::momentumYBalanceIdx);
#else
//consider orientation of face automatically
values.setCouplingNeumann(scvf.directionIndex());
#endif
#if EXNUMBER == 2
// set the Beaver-Joseph-Saffman slip condition for the tangential momentum balance equation
values.setBJS(Indices::momentumXBalanceIdx);
#endif
#if EXNUMBER == 3
// set the Beaver-Joseph-Saffman slip condition for the tangential momentum balance equation,
// consider orientation of face automatically
values.setBJS(1 - scvf.directionIndex());
#endif
}
return values;
}
/*!
* \brief Evaluate the boundary conditions for a Dirichlet control volume.
*
* \param globalPos The global position
*/
PrimaryVariables dirichletAtPos(const GlobalPosition& globalPos) const
{
PrimaryVariables values(0.0);
values = initialAtPos(globalPos);
return values;
}
/*!
* \brief Evaluate the boundary conditions for a Neumann control volume.
*
* \param element The element for which the Neumann boundary condition is set
* \param fvGeomentry The fvGeometry
* \param elemVolVars The element volume variables
* \param elemFaceVars The element face variables
* \param scvf The boundary sub control volume face
*/
template<class ElementVolumeVariables, class ElementFaceVariables>
NumEqVector neumann(const Element& element,
const FVElementGeometry& fvGeometry,
const ElementVolumeVariables& elemVolVars,
const ElementFaceVariables& elemFaceVars,
const SubControlVolumeFace& scvf) const
{
NumEqVector values(0.0);
if(couplingManager().isCoupledEntity(CouplingManager::stokesIdx, scvf))
{
values[Indices::conti0EqIdx] = couplingManager().couplingData().massCouplingCondition(fvGeometry, elemVolVars, elemFaceVars, scvf);
#if EXNUMBER < 3
values[Indices::momentumYBalanceIdx] = couplingManager().couplingData().momentumCouplingCondition(fvGeometry, elemVolVars, elemFaceVars, scvf);
#else
values[scvf.directionIndex()] = couplingManager().couplingData().momentumCouplingCondition(fvGeometry, elemVolVars, elemFaceVars, scvf);
#endif
}
return values;
}
// \}
//! Set the coupling manager
void setCouplingManager(std::shared_ptr<CouplingManager> cm)
{ couplingManager_ = cm; }
//! Get the coupling manager
const CouplingManager& couplingManager() const
{ return *couplingManager_; }
/*!
* \name Volume terms
*/
// \{
/*!
* \brief Evaluate the initial value for a control volume.
*
* \param globalPos The global position
*/
PrimaryVariables initialAtPos(const GlobalPosition &globalPos) const
{
PrimaryVariables values(0.0);
#if EXNUMBER == 0
values[Indices::velocityYIdx] = -1e-6 * globalPos[0] * (this->fvGridGeometry().bBoxMax()[0] - globalPos[0]);
#else
// set fixed pressures on the left and right boundary
if(onLeftBoundary_(globalPos))
values[Indices::pressureIdx] = deltaP_;
if(onRightBoundary_(globalPos))
values[Indices::pressureIdx] = 0.0;
#endif
return values;
}
/*!
* \brief Returns the intrinsic permeability of required as input parameter for the Beavers-Joseph-Saffman boundary condition
*/
Scalar permeability(const SubControlVolumeFace& scvf) const
{
return couplingManager().couplingData().darcyPermeability(scvf);
}
/*!
* \brief Returns the alpha value required as input parameter for the Beavers-Joseph-Saffman boundary condition
*/
Scalar alphaBJ(const SubControlVolumeFace& scvf) const
{
return couplingManager().problem(CouplingManager::darcyIdx).spatialParams().beaversJosephCoeffAtPos(scvf.center());
}
/*!
* \brief calculate the analytical velocity in x direction based on Beavers & Joseph (1967)
*/
void calculateAnalyticalVelocityX() const
{
analyticalVelocityX_.resize(this->fvGridGeometry().gridView().size(0));
using std::sqrt;
const Scalar dPdX = -deltaP_ / (this->fvGridGeometry().bBoxMax()[0] - this->fvGridGeometry().bBoxMin()[0]);
static const Scalar mu = FluidSystem::viscosity(temperature(), 1e5);
static const Scalar alpha = getParam<Scalar>("Darcy.SpatialParams.AlphaBeaversJoseph");
static const Scalar K = getParam<Scalar>("Darcy.SpatialParams.Permeability");
static const Scalar sqrtK = sqrt(K);
const Scalar sigma = (this->fvGridGeometry().bBoxMax()[1] - this->fvGridGeometry().bBoxMin()[1])/sqrtK;
const Scalar uB = -K/(2.0*mu) * ((sigma*sigma + 2.0*alpha*sigma) / (1.0 + alpha*sigma)) * dPdX;
for (const auto& element : elements(this->fvGridGeometry().gridView()))
{
const auto eIdx = this->fvGridGeometry().gridView().indexSet().index(element);
const Scalar y = element.geometry().center()[1] - this->fvGridGeometry().bBoxMin()[1];
const Scalar u = uB*(1.0 + alpha/sqrtK*y) + 1.0/(2.0*mu) * (y*y + 2*alpha*y*sqrtK) * dPdX;
analyticalVelocityX_[eIdx] = u;
}
}
/*!
* \brief Get the analytical velocity in x direction
*/
const std::vector<Scalar>& getAnalyticalVelocityX() const
{
if(analyticalVelocityX_.empty())
calculateAnalyticalVelocityX();
return analyticalVelocityX_;
}
// \}
private:
bool onLeftBoundary_(const GlobalPosition &globalPos) const
{ return globalPos[0] < this->fvGridGeometry().bBoxMin()[0] + eps_; }
bool onRightBoundary_(const GlobalPosition &globalPos) const
{ return globalPos[0] > this->fvGridGeometry().bBoxMax()[0] - eps_; }
bool onLowerBoundary_(const GlobalPosition &globalPos) const
{ return globalPos[1] < this->fvGridGeometry().bBoxMin()[1] + eps_; }
bool onUpperBoundary_(const GlobalPosition &globalPos) const
{ return globalPos[1] > this->fvGridGeometry().bBoxMax()[1] - eps_; }
Scalar eps_;
Scalar deltaP_;
std::shared_ptr<CouplingManager> couplingManager_;
mutable std::vector<Scalar> analyticalVelocityX_;
};
} //end namespace
#endif // DUMUX_STOKES_SUBPROBLEM_HH
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
// vi: set et ts=4 sw=4 sts=4:
/*****************************************************************************
* See the file COPYING for full copying permissions. *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
*****************************************************************************/
/*!
* \file
*
* \brief The porous medium flow sub problem
*/
#ifndef DUMUX_DARCY_SUBPROBLEM_HH
#define DUMUX_DARCY_SUBPROBLEM_HH
#include <dune/grid/yaspgrid.hh>
#if EXNUMBER >= 3
#include <dumux/io/grid/subgridgridcreator.hh>
#endif
#include <dumux/discretization/cellcentered/tpfa/properties.hh>
#include <dumux/porousmediumflow/1p/model.hh>
#include <dumux/porousmediumflow/problem.hh>
#include "1pspatialparams.hh"
#include <dumux/material/components/simpleh2o.hh>
#include <dumux/material/fluidsystems/1pliquid.hh>
namespace Dumux
{
template <class TypeTag>
class DarcySubProblem;
namespace Properties
{
NEW_TYPE_TAG(DarcyOnePTypeTag, INHERITS_FROM(CCTpfaModel, OneP));
// Set the problem property
SET_TYPE_PROP(DarcyOnePTypeTag, Problem, Dumux::DarcySubProblem<TypeTag>);
// the fluid system
SET_PROP(DarcyOnePTypeTag, FluidSystem)
{
using Scalar = typename GET_PROP_TYPE(TypeTag, Scalar);
using type = FluidSystems::OnePLiquid<Scalar, Dumux::Components::SimpleH2O<Scalar> > ;
};
// Set the grid type
SET_PROP(DarcyOnePTypeTag, Grid)
{
static constexpr auto dim = 2;
using Scalar = typename GET_PROP_TYPE(TypeTag, Scalar);
using TensorGrid = Dune::YaspGrid<2, Dune::TensorProductCoordinates<Scalar, dim> >;
#if EXNUMBER < 3 // use "normal" grid
using type = TensorGrid;
#else // use dune-subgrid
using HostGrid = TensorGrid;
using type = Dune::SubGrid<dim, HostGrid>;
#endif
};
SET_TYPE_PROP(DarcyOnePTypeTag, SpatialParams, OnePSpatialParams<TypeTag>);
}
/*!
* \brief The porous medium flow sub problem
*/
template <class TypeTag>
class DarcySubProblem : public PorousMediumFlowProblem<TypeTag>
{
using ParentType = PorousMediumFlowProblem<TypeTag>;
using GridView = typename GET_PROP_TYPE(TypeTag, GridView);
using Scalar = typename GET_PROP_TYPE(TypeTag, Scalar);
using PrimaryVariables = typename GET_PROP_TYPE(TypeTag, PrimaryVariables);
using NumEqVector = typename GET_PROP_TYPE(TypeTag, NumEqVector);
using BoundaryTypes = typename GET_PROP_TYPE(TypeTag, BoundaryTypes);
using VolumeVariables = typename GET_PROP_TYPE(TypeTag, VolumeVariables);
using FVElementGeometry = typename GET_PROP_TYPE(TypeTag, FVGridGeometry)::LocalView;
using SubControlVolume = typename FVElementGeometry::SubControlVolume;
using SubControlVolumeFace = typename FVElementGeometry::SubControlVolumeFace;
using FVGridGeometry = typename GET_PROP_TYPE(TypeTag, FVGridGeometry);
using Indices = typename GET_PROP_TYPE(TypeTag, ModelTraits)::Indices;
using Element = typename GridView::template Codim<0>::Entity;
using GlobalPosition = typename Element::Geometry::GlobalCoordinate;
using CouplingManager = typename GET_PROP_TYPE(TypeTag, CouplingManager);
public:
DarcySubProblem(std::shared_ptr<const FVGridGeometry> fvGridGeometry,
std::shared_ptr<CouplingManager> couplingManager)
: ParentType(fvGridGeometry, "Darcy"), eps_(1e-7), couplingManager_(couplingManager)
{}
/*!
* \name Simulation steering
*/
// \{
/*!
* \brief Return the temperature within the domain in [K].
*
*/
Scalar temperature() const
{ return 273.15 + 10; } // 10°C
// \}
/*!
* \name Boundary conditions
*/
// \{
/*!
* \brief Specifies which kind of boundary condition should be
* used for which equation on a given boundary control volume.
*
* \param element The element
* \param scvf The boundary sub control volume face
*/
BoundaryTypes boundaryTypes(const Element &element, const SubControlVolumeFace &scvf) const
{
BoundaryTypes values;
values.setAllNeumann();
#if EXNUMBER == 0 // flow from top to bottom
if (onLowerBoundary_(scvf.center()))
values.setAllDirichlet();
#endif
if (couplingManager().isCoupledEntity(CouplingManager::darcyIdx, scvf))
values.setAllCouplingNeumann();
return values;
}
/*!
* \brief Evaluate the boundary conditions for a Dirichlet control volume.
*
* \param element The element for which the Dirichlet boundary condition is set
* \param scvf The boundary subcontrolvolumeface
*
* For this method, the \a values parameter stores primary variables.
*/
PrimaryVariables dirichlet(const Element &element, const SubControlVolumeFace &scvf) const
{
PrimaryVariables values(0.0);
values = initial(element);
return values;
}
/*!
* \brief Evaluate the boundary conditions for a Neumann control volume.
*
* \param element The element for which the Neumann boundary condition is set
* \param fvGeomentry The fvGeometry
* \param elemVolVars The element volume variables
* \param scvf The boundary sub control volume face
*
* For this method, the \a values variable stores primary variables.
*/
template<class ElementVolumeVariables>
NumEqVector neumann(const Element& element,
const FVElementGeometry& fvGeometry,
const ElementVolumeVariables& elemVolVars,
const SubControlVolumeFace& scvf) const
{
NumEqVector values(0.0);
if (couplingManager().isCoupledEntity(CouplingManager::darcyIdx, scvf))
values[Indices::conti0EqIdx] = couplingManager().couplingData().massCouplingCondition(fvGeometry, elemVolVars, scvf);
return values;
}
// \}
/*!
* \name Volume terms
*/
// \{
/*!
* \brief Evaluate the source term for all phases within a given
* sub-control-volume.
*
* \param element The element for which the source term is set
* \param fvGeomentry The fvGeometry
* \param elemVolVars The element volume variables
* \param scv The subcontrolvolume
*/
template<class ElementVolumeVariables>
NumEqVector source(const Element &element,
const FVElementGeometry& fvGeometry,
const ElementVolumeVariables& elemVolVars,
const SubControlVolume &scv) const
{ return NumEqVector(0.0); }
// \}
/*!
* \brief Evaluate the initial value for a control volume.
*
* \param element The element
*
* For this method, the \a priVars parameter stores primary
* variables.
*/
PrimaryVariables initial(const Element &element) const
{
return PrimaryVariables(0.0);
}
// \}
//! Set the coupling manager
void setCouplingManager(std::shared_ptr<CouplingManager> cm)
{ couplingManager_ = cm; }
//! Get the coupling manager
const CouplingManager& couplingManager() const
{ return *couplingManager_; }
private:
bool onLeftBoundary_(const GlobalPosition &globalPos) const
{ return globalPos[0] < this->fvGridGeometry().bBoxMin()[0] + eps_; }
bool onRightBoundary_(const GlobalPosition &globalPos) const
{ return globalPos[0] > this->fvGridGeometry().bBoxMax()[0] - eps_; }
bool onLowerBoundary_(const GlobalPosition &globalPos) const
{ return globalPos[1] < this->fvGridGeometry().bBoxMin()[1] + eps_; }
bool onUpperBoundary_(const GlobalPosition &globalPos) const
{ return globalPos[1] > this->fvGridGeometry().bBoxMax()[1] - eps_; }
Scalar eps_;
std::shared_ptr<CouplingManager> couplingManager_;
};
} //end namespace
#endif //DUMUX_DARCY_SUBPROBLEM_HH
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment