// -*- 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 . *
*****************************************************************************/
/*!
* \file
*
* \brief The two-phase porousmediumflow problem for exercise runtime parameters
*/
#ifndef DUMUX_EXRUNTIMEPARAMS_INJECTION_PROBLEM_2P_HH
#define DUMUX_EXRUNTIMEPARAMS_INJECTION_PROBLEM_2P_HH
#include
#include
#include
#include
#include
#include "injection2pspatialparams.hh"
namespace Dumux {
// forward declare problem
template
class InjectionProblem2P;
namespace Properties {
// define the TypeTag for this problem with a cell-centered two-point flux approximation spatial discretization.
// Create new type tags
namespace TTag {
struct Injection2p { using InheritsFrom = std::tuple; };
struct Injection2pCC { using InheritsFrom = std::tuple; };
} // end namespace TTag
// Set the grid type
template
struct Grid { using type = Dune::YaspGrid<2>; };
// Set the problem property
template
struct Problem { using type = InjectionProblem2P; };
// Set the spatial parameters
SET_TYPE_PROP(Injection2p, SpatialParams,
InjectionSpatialParams,
GetPropType>);
// Set fluid configuration
template
struct FluidSystem { using type = FluidSystems::H2ON2, FluidSystems::H2ON2DefaultPolicy*fastButSimplifiedRelations=*/ true>>; };
} // end namespace Properties
/*!
* \ingroup TwoPModel
* \ingroup ImplicitTestProblems
* \brief Gas injection problem where a gas (here nitrogen) is injected into a fully
* water saturated medium. During buoyancy driven upward migration the gas
* passes a high temperature area.
*
* The domain is sized 60 m times 40 m.
*
* For the mass conservation equation neumann boundary conditions are used on
* the top, on the bottom and on the right of the domain, while dirichlet conditions
* apply on the left boundary.
*
* Gas is injected at the right boundary from 7 m to 15 m at a rate of
* 0.001 kg/(s m), the remaining neumann boundaries are no-flow
* boundaries.
*
* At the dirichlet boundaries a hydrostatic pressure and a gas saturation of zero a
*
* This problem uses the \ref TwoPModel model.
*/
template
class InjectionProblem2P : public PorousMediumFlowProblem
{
using ParentType = PorousMediumFlowProblem;
using GridView = GetPropType;
using Scalar = GetPropType;
using Indices = typename GetPropType::Indices;
using PrimaryVariables = GetPropType;
using BoundaryTypes = GetPropType;
using FVGridGeometry = GetPropType;
using FVElementGeometry = typename GetPropType::LocalView;
using FluidSystem = GetPropType;
enum { dimWorld = GridView::dimensionworld };
using Element = typename GridView::template Codim<0>::Entity;
using GlobalPosition = typename Element::Geometry::GlobalCoordinate;
public:
InjectionProblem2P(std::shared_ptr fvGridGeometry)
: ParentType(fvGridGeometry)
{
// initialize the tables of the fluid system
FluidSystem::init(/*tempMin=*/273.15,
/*tempMax=*/423.15,
/*numTemp=*/50,
/*pMin=*/0.0,
/*pMax=*/30e6,
/*numP=*/300);
// name of the problem and output file
// getParam("GROUPNAME.PARAMNAME") reads and sets parameter PARAMNAME
// of type TYPE given in the group GROUPNAME from the input file
name_ = getParam("Problem.Name");
// depth of the aquifer, units: m
aquiferDepth_ = getParam("Problem.AquiferDepth");
// the duration of the injection, units: second
injectionDuration_ = getParamFromGroup("Problem","InjectionDuration");
//TODO: Task 2: Set a variable "TotalAreaSpecificInflow" to read in a value from the parameter tree via the input file
totalAreaSpecificInflow_ = getParam("Problem.TotalAreaSpecificInflow");
//TODO: Task 3: Set a default value for the above parameter.
// totalAreaSpecificInflow_ = getParam("Problem.TotalAreaSpecificInflow", -1e-4);
//TODO: Task 4: Provide output describing where the parameter value comes from using parameter bool functions.
// if (hasParamInGroup("Problem","TotalAreaSpecificInflow"))
// std::cout << "Parameter value is read from the input file." << std::endl;
// else
// std::cout << "Using the default parameter value." << std::endl;
}
/*!
* \name Problem parameters
*/
// \{
/*!
* \brief Returns the problem name
*
* This is used as a prefix for files generated by the simulation.
*/
std::string name() const
{ return name_+"-2p"; }
/*!
* \brief Returns the temperature \f$ K \f$
*/
Scalar temperature() const
{
return 273.15 + 30; // [K]
}
// \}
/*!
* \name Boundary conditions
*/
// \{
/*!
* \brief Specifies which kind of boundary condition should be
* used for which equation on a given boundary segment.
*
* \param globalPos The position for which the bc type should be evaluated
*/
BoundaryTypes boundaryTypesAtPos(const GlobalPosition &globalPos) const
{
BoundaryTypes bcTypes;
// set the left of the domain (with the global position in "0 = x" direction as a Dirichlet boundary
if (globalPos[0] < eps_)
bcTypes.setAllDirichlet();
// set all other as Neumann boundaries
else
bcTypes.setAllNeumann();
return bcTypes;
}
/*!
* \brief Evaluates the boundary conditions for a Dirichlet
* boundary segment
*
* \param globalPos The global position
*/
PrimaryVariables dirichletAtPos(const GlobalPosition &globalPos) const
{
return initialAtPos(globalPos);
}
/*!
* \brief Evaluate the boundary conditions for a neumann
* boundary segment.
*
* \param globalPos The position of the integration point of the boundary segment.
*/
PrimaryVariables neumannAtPos(const GlobalPosition &globalPos) const
{
// initialize values to zero, i.e. no-flow Neumann boundary conditions
PrimaryVariables values(0.0);
// if we are inside the injection zone set inflow Neumann boundary conditions
// using < boundary + eps_ or > boundary - eps_ is safer for floating point comparisons
// than using <= or >= as it is robust with regard to imprecision introduced by rounding errors.
if (time_ < injectionDuration_
&& globalPos[1] < 15 + eps_ && globalPos[1] > 7 - eps_ && globalPos[0] > 0.9*this->fvGridGeometry().bBoxMax()[0])
{
// inject nitrogen. negative values mean injection
// units kg/(s*m^2)
//TODO: Task 2: incorporate "totalAreaSpecificInflow_" into the injection boundary condition
values[Indices::conti0EqIdx + FluidSystem::N2Idx] = totalAreaSpecificInflow_/FluidSystem::molarMass(FluidSystem::N2Idx);
values[Indices::conti0EqIdx + FluidSystem::H2OIdx] = 0.0;
}
return values;
}
// \}
/*!
* \name Volume terms
*/
// \{
/*!
* \brief Evaluate the initial value for a control volume.
*
* \param globalPos The position for which the initial condition should be evaluated
*/
PrimaryVariables initialAtPos(const GlobalPosition &globalPos) const
{
PrimaryVariables values(0.0);
// get the water density at atmospheric conditions
const Scalar densityW = FluidSystem::H2O::liquidDensity(temperature(), 1.0e5);
// assume an intially hydrostatic liquid pressure profile
// note: we subtract rho_w*g*h because g is defined negative
const Scalar pw = 1.0e5 - densityW*this->gravity()[dimWorld-1]*(aquiferDepth_ - globalPos[dimWorld-1]);
values[Indices::pressureIdx] = pw;
values[Indices::saturationIdx] = 0.0;
return values;
}
// \}
//! set the time for the time dependent boundary conditions (called from main)
void setTime(Scalar time)
{ time_ = time; }
private:
static constexpr Scalar eps_ = 1e-6;
std::string name_; //! Problem name
Scalar aquiferDepth_; //! Depth of the aquifer in m
Scalar injectionDuration_; //! Duration of the injection in seconds
//TODO: Task 2: Set a variable "totalAreaSpecificInflow_" to read in a value from the parameter tree via the input file
Scalar totalAreaSpecificInflow_; //! Rate of the Injection in kg/(s m^2)
Scalar time_;
};
} //end namespace Dumux
#endif