From a2ef462452fa006f355ce9162fef52ec381a6774 Mon Sep 17 00:00:00 2001 From: Katharina Heck Date: Thu, 14 Sep 2017 11:02:30 +0200 Subject: [PATCH 01/42] [tutorial] add first exercise for dumux-course --- tutorial/dumux-course/CMakeLists.txt | 5 + tutorial/dumux-course/exercise1.input | 15 + tutorial/dumux-course/exercise1_2p.cc | 64 +++ tutorial/dumux-course/exercise1_2p2c.cc | 67 ++++ tutorial/dumux-course/injection2p2cproblem.hh | 367 ++++++++++++++++++ tutorial/dumux-course/injection2pproblem.hh | 282 ++++++++++++++ .../dumux-course/injection2pspatialparams.hh | 242 ++++++++++++ 7 files changed, 1042 insertions(+) create mode 100644 tutorial/dumux-course/CMakeLists.txt create mode 100755 tutorial/dumux-course/exercise1.input create mode 100755 tutorial/dumux-course/exercise1_2p.cc create mode 100644 tutorial/dumux-course/exercise1_2p2c.cc create mode 100644 tutorial/dumux-course/injection2p2cproblem.hh create mode 100644 tutorial/dumux-course/injection2pproblem.hh create mode 100644 tutorial/dumux-course/injection2pspatialparams.hh diff --git a/tutorial/dumux-course/CMakeLists.txt b/tutorial/dumux-course/CMakeLists.txt new file mode 100644 index 0000000000..4b342a63b9 --- /dev/null +++ b/tutorial/dumux-course/CMakeLists.txt @@ -0,0 +1,5 @@ +add_executable(exercise1_2p exercise1_2p.cc exercise1_2p.cc) + +add_executable(exercise1_2p2c exercise1_2p2c.cc exercise1_2p2c.cc) + +dune_symlink_to_source_files(FILES "exercise1.input") diff --git a/tutorial/dumux-course/exercise1.input b/tutorial/dumux-course/exercise1.input new file mode 100755 index 0000000000..2e400a0bb7 --- /dev/null +++ b/tutorial/dumux-course/exercise1.input @@ -0,0 +1,15 @@ +[TimeManager] +DtInitial = 250 # [s] +TEnd = 1e7 # [s] + +[Grid] +LowerLeft = 0 0 +UpperRight = 60 40 +Cells = 24 16 + +[Problem] +MaxDepth = 2700.0 + +[Newton] +WriteConvergence = 1 # write convergence behaviour to disk? + diff --git a/tutorial/dumux-course/exercise1_2p.cc b/tutorial/dumux-course/exercise1_2p.cc new file mode 100755 index 0000000000..6152aa5d20 --- /dev/null +++ b/tutorial/dumux-course/exercise1_2p.cc @@ -0,0 +1,64 @@ +// -*- 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 DOC ME! + */ +#include "config.h" +#include "injection2pproblem.hh" +#include + +/*! + * \brief Provides an interface for customizing error messages associated with + * reading in parameters. + * + * \param progName The name of the program, that was tried to be started. + * \param errorMsg The error message that was issued by the start function. + * Comprises the thing that went wrong and a general help message. + */ +void usage(const char *progName, const std::string &errorMsg) +{ + if (errorMsg.size() > 0) { + std::string errorMessageOut = "\nUsage: "; + errorMessageOut += progName; + errorMessageOut += " [options]\n"; + errorMessageOut += errorMsg; + errorMessageOut += "\n\nThe list of mandatory options for this program is:\n" + "\t-TimeManager.TEnd End of the simulation [s] \n" + "\t-TimeManager.DtInitial Initial timestep size [s] \n" + "\t-Grid.File Name of the file containing the grid \n" + "\t definition in DGF format\n" + "\t-SpatialParams.LensLowerLeft coordinates of the lower left corner of the lens [m] \n" + "\t-SpatialParams.LensUpperRight coordinates of the upper right corner of the lens [m] \n" + "\t-Problem.Name String for naming of the output files \n" + "\n"; + std::cout << errorMessageOut + << "\n"; + } +} + +//////////////////////// +// the main function +//////////////////////// +int main(int argc, char** argv) +{ + typedef TTAG(InjectionCCProblem2P) ProblemTypeTag; + return Dumux::start(argc, argv, usage); +} diff --git a/tutorial/dumux-course/exercise1_2p2c.cc b/tutorial/dumux-course/exercise1_2p2c.cc new file mode 100644 index 0000000000..aba0b0e8c7 --- /dev/null +++ b/tutorial/dumux-course/exercise1_2p2c.cc @@ -0,0 +1,67 @@ +// -*- 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 Test for the two-phase two-component CC model. + */ +#include +#include "injection2p2cproblem.hh" +#include + +/*! + * \brief Provides an interface for customizing error messages associated with + * reading in parameters. + * + * \param progName The name of the program, that was tried to be started. + * \param errorMsg The error message that was issued by the start function. + * Comprises the thing that went wrong and a general help message. + */ +void usage(const char *progName, const std::string &errorMsg) +{ + if (errorMsg.size() > 0) { + std::string errorMessageOut = "\nUsage: "; + errorMessageOut += progName; + errorMessageOut += " [options]\n"; + errorMessageOut += errorMsg; + errorMessageOut += "\n\nThe list of mandatory options for this program is:\n" + "\t-TimeManager.TEnd End of the simulation [s] \n" + "\t-TimeManager.DtInitial Initial timestep size [s] \n" + "\t-Grid.File Name of the file containing the grid \n" + "\t definition in DGF format\n" + "\t-FluidSystem.NTemperature Number of tabularization entries [-] \n" + "\t-FluidSystem.NPressure Number of tabularization entries [-] \n" + "\t-FluidSystem.PressureLow Low end for tabularization of fluid properties [Pa] \n" + "\t-FluidSystem.PressureHigh High end for tabularization of fluid properties [Pa] \n" + "\t-FluidSystem.TemperatureLow Low end for tabularization of fluid properties [Pa] \n" + "\t-FluidSystem.TemperatureHigh High end for tabularization of fluid properties [Pa] \n" + "\t-SimulationControl.Name The name of the output files [-] \n" + "\t-InitialConditions.Temperature Initial temperature in the reservoir [K] \n" + "\t-InitialConditions.DepthBOR Depth below ground surface [m] \n"; + + std::cout << errorMessageOut + << "\n"; + } +} + +int main(int argc, char** argv) +{ + typedef TTAG(Injection2p2pcCCProblem) ProblemTypeTag; + return Dumux::start(argc, argv, usage); +} diff --git a/tutorial/dumux-course/injection2p2cproblem.hh b/tutorial/dumux-course/injection2p2cproblem.hh new file mode 100644 index 0000000000..3ffe656288 --- /dev/null +++ b/tutorial/dumux-course/injection2p2cproblem.hh @@ -0,0 +1,367 @@ +// -*- 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 Problem where air is injected under a low permeable layer in a depth of 2700m. + */ +#ifndef DUMUX_INJECTION_2P2C_PROBLEM_HH +#define DUMUX_INJECTION_2P2C_PROBLEM_HH + +#include +#include +#include + +#include "injection2pspatialparams.hh" + +namespace Dumux +{ + +template +class Injection2p2cProblem; + +namespace Properties +{ +NEW_TYPE_TAG(Injection2p2cProblem, INHERITS_FROM(TwoPTwoC, InjectionSpatialParams)); +NEW_TYPE_TAG(Injection2p2cBoxProblem, INHERITS_FROM(BoxModel, Injection2p2cProblem)); +NEW_TYPE_TAG(Injection2p2pcCCProblem, INHERITS_FROM(CCModel, Injection2p2cProblem)); + +// Set the grid type +SET_TYPE_PROP(Injection2p2cProblem, Grid, Dune::YaspGrid<2>); + +// Set the problem property +SET_TYPE_PROP(Injection2p2cProblem, Problem, Injection2p2cProblem); + +// Set fluid configuration +SET_TYPE_PROP(Injection2p2cProblem, + FluidSystem, + FluidSystems::H2ON2); + +// Define whether mole(true) or mass (false) fractions are used +SET_BOOL_PROP(Injection2p2cProblem, UseMoles, true); +} + + +/*! + * \ingroup TwoPTwoCModel + * \ingroup ImplicitTestProblems + * \brief Problem where air is injected under a low permeable layer in a depth of 2700m. + * + * The domain is sized 60m times 40m and consists of two layers, a moderately + * permeable one (\f$ K=10e-12\f$) for \f$ y<22m\f$ and one with a lower permeablility (\f$ K=10e-13\f$) + * in the rest of the domain. + * + * A mixture of Nitrogen and Water vapor, which is composed according to the prevailing conditions (temperature, pressure) + * enters a water-filled aquifer. This is realized with a solution-dependent Neumann boundary condition at the right boundary + * (\f$ 5m./exercise1_2p2c -parameterFile exercise1.input> + */ +template +class Injection2p2cProblem : public ImplicitPorousMediaProblem +{ + typedef ImplicitPorousMediaProblem ParentType; + + typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; + typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; + typedef typename GET_PROP_TYPE(TypeTag, FluidSystem) FluidSystem; + + enum { + // Grid and world dimension + dim = GridView::dimension, + dimWorld = GridView::dimensionworld + }; + + // copy some indices for convenience + typedef typename GET_PROP_TYPE(TypeTag, Indices) Indices; + enum { + wPhaseIdx = Indices::wPhaseIdx, + nPhaseIdx = Indices::nPhaseIdx, + + + wCompIdx = FluidSystem::wCompIdx, + nCompIdx = FluidSystem::nCompIdx, + + contiH2OEqIdx = Indices::contiWEqIdx, + contiN2EqIdx = Indices::contiNEqIdx + }; + + + typedef typename GET_PROP_TYPE(TypeTag, PrimaryVariables) PrimaryVariables; + typedef typename GET_PROP_TYPE(TypeTag, ElementVolumeVariables) ElementVolumeVariables; + typedef typename GET_PROP_TYPE(TypeTag, BoundaryTypes) BoundaryTypes; + typedef typename GET_PROP_TYPE(TypeTag, TimeManager) TimeManager; + + typedef typename GridView::template Codim<0>::Entity Element; + typedef typename GridView::template Codim::Entity Vertex; + typedef typename GridView::Intersection Intersection; + + typedef typename GET_PROP_TYPE(TypeTag, FVElementGeometry) FVElementGeometry; + + typedef Dune::FieldVector GlobalPosition; + + enum { isBox = GET_PROP_VALUE(TypeTag, ImplicitIsBox) }; + + //! property that defines whether mole or mass fractions are used + static const bool useMoles = GET_PROP_VALUE(TypeTag, UseMoles); + +public: + /*! + * \brief The constructor + * + * \param timeManager The time manager + * \param gridView The grid view + */ + Injection2p2cProblem(TimeManager &timeManager, + const GridView &gridView) + : ParentType(timeManager, gridView) + { + maxDepth_ = GET_RUNTIME_PARAM(TypeTag, Scalar, Problem.MaxDepth); + + // initialize the tables of the fluid system + FluidSystem::init(/*tempMin=*/273.15, + /*tempMax=*/423.15, + /*numTemp=*/50, + /*pMin=*/0.0, + /*pMax=*/30e6, + /*numP=*/300); + + //stateing in the console whether mole or mass fractions are used + if(useMoles) + { + std::cout<<"problem uses mole-fractions"<model().globalPhaseStorage(storageW, wPhaseIdx); + this->model().globalPhaseStorage(storageN, nPhaseIdx); + + // Write mass balance information for rank 0 + if (this->gridView().comm().rank() == 0) { + std::cout<<"Storage: wetting=[" << storageW << "]" + << " nonwetting=[" << storageN << "]\n"; + } + } + + + /*! + * \name Problem parameters + */ + // \{ + + /*! + * \brief Returns the problem name + * + * This is used as a prefix for files generated by the simulation. + */ + const std::string name() const + { return "injection-2p2c"; } + + /*! + * \brief Returns the temperature \f$ K \f$ + */ + Scalar temperature() const + { + return 273.15 + 30; // [K] + } + + /*! + * \brief Returns the source term + * + * \param values Stores the source values for the conservation equations in + * \f$ [ \textnormal{unit of primary variable} / (m^\textrm{dim} \cdot s )] \f$ + * \param globalPos The global position + */ + void sourceAtPos(PrimaryVariables &values, + const GlobalPosition &globalPos) const + { + values = 0; + } + + // \} + + /*! + * \name Boundary conditions + */ + // \{ + + /*! + * \brief Specifies which kind of boundary condition should be + * used for which equation on a given boundary segment + * + * \param values Stores the value of the boundary type + * \param globalPos The global position + */ + void boundaryTypesAtPos(BoundaryTypes &values, + const GlobalPosition &globalPos) const + { + if (globalPos[0] < eps_) + values.setAllDirichlet(); + else + values.setAllNeumann(); + } + + /*! + * \brief Evaluates the boundary conditions for a Dirichlet + * boundary segment + * + * \param values Stores the Dirichlet values for the conservation equations in + * \f$ [ \textnormal{unit of primary variable} ] \f$ + * \param globalPos The global position + */ + void dirichletAtPos(PrimaryVariables &values, const GlobalPosition &globalPos) const + { + initial_(values, globalPos); + } + + /*! + * \brief Evaluates the boundary conditions for a Neumann + * boundary segment in dependency on the current solution. + * + * \param values Stores the Neumann values for the conservation equations in + * \f$ [ \textnormal{unit of conserved quantity} / (m^(dim-1) \cdot s )] \f$ + * \param element The finite element + * \param fvGeometry The finite volume geometry of the element + * \param intersection The intersection between element and boundary + * \param scvIdx The local index of the sub-control volume + * \param boundaryFaceIdx The index of the boundary face + * \param elemVolVars All volume variables for the element + * + * This method is used for cases, when the Neumann condition depends on the + * solution and requires some quantities that are specific to the fully-implicit method. + * The \a values store the mass flux of each phase normal to the boundary. + * Negative values indicate an inflow. + */ + void solDependentNeumann(PrimaryVariables &values, + const Element &element, + const FVElementGeometry &fvGeometry, + const Intersection &intersection, + const int scvIdx, + const int boundaryFaceIdx, + const ElementVolumeVariables &elemVolVars) const + { + values = 0; + + GlobalPosition globalPos; + if (isBox) + globalPos = element.geometry().corner(scvIdx); + else + globalPos = intersection.geometry().center(); + + Scalar injectedPhaseMass = 1e-3; + Scalar moleFracW = elemVolVars[scvIdx].moleFraction(nPhaseIdx, wCompIdx); + if (globalPos[1] < 15 + eps_ && globalPos[1] > 7 -eps_) { + values[contiN2EqIdx] = -(1-moleFracW)*injectedPhaseMass/FluidSystem::molarMass(nCompIdx); //mole/(m^2*s) -> kg/(s*m^2) + values[contiH2OEqIdx] = -moleFracW*injectedPhaseMass/FluidSystem::molarMass(wCompIdx); //mole/(m^2*s) -> kg/(s*m^2) + } + } + + // \} + + /*! + * \name Volume terms + */ + // \{ + + /*! + * \brief Evaluates the initial values for a control volume + * + * \param values Stores the initial values for the conservation equations in + * \f$ [ \textnormal{unit of primary variables} ] \f$ + * \param globalPos The global position + */ + void initialAtPos(PrimaryVariables &values, const GlobalPosition &globalPos) const + { + initial_(values, globalPos); + } + + /*! + * \brief Return the initial phase state inside a control volume. + * + * \param globalPos The global position + */ + int initialPhasePresenceAtPos(const GlobalPosition &globalPos) const + { return Indices::wPhaseOnly; } + + // \} + +private: + /*! + * \brief Evaluates the initial values for a control volume + * + * The internal method for the initial condition + * + * \param values Stores the initial values for the conservation equations in + * \f$ [ \textnormal{unit of primary variables} ] \f$ + * \param globalPos The global position + */ + void initial_(PrimaryVariables &values, + const GlobalPosition &globalPos) const + { + Scalar densityW = FluidSystem::H2O::liquidDensity(temperature(), 1e5); + + Scalar pl = 1e5 - densityW*this->gravity()[1]*(maxDepth_ - globalPos[1]); + Scalar moleFracLiquidN2 = pl*0.95/BinaryCoeff::H2O_N2::henry(temperature()); + Scalar moleFracLiquidH2O = 1.0 - moleFracLiquidN2; + + Scalar meanM = + FluidSystem::molarMass(wCompIdx)*moleFracLiquidH2O + + FluidSystem::molarMass(nCompIdx)*moleFracLiquidN2; + if(useMoles) + { + //mole-fraction formulation + values[Indices::switchIdx] = moleFracLiquidN2; + } + else + { + //mass fraction formulation + Scalar massFracLiquidN2 = moleFracLiquidN2*FluidSystem::molarMass(nCompIdx)/meanM; + values[Indices::switchIdx] = massFracLiquidN2; + } + values[Indices::pressureIdx] = pl; + } + + + static constexpr Scalar eps_ = 1e-6; + Scalar maxDepth_; + +}; +} //end namespace + +#endif diff --git a/tutorial/dumux-course/injection2pproblem.hh b/tutorial/dumux-course/injection2pproblem.hh new file mode 100644 index 0000000000..eba0e274cf --- /dev/null +++ b/tutorial/dumux-course/injection2pproblem.hh @@ -0,0 +1,282 @@ +// -*- 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 Non-isothermal gas injection problem where a gas (e.g. air) is injected into a fully + * water saturated medium. During buoyancy driven upward migration the gas + * passes a high temperature area. + */ + +#ifndef DUMUX_INJECTION_PROBLEM_2P_HH +#define DUMUX_INJECTION_PROBLEM_2P_HH + +#include +#include + +#include + +#include "injection2pspatialparams.hh" + +namespace Dumux { + +template +class InjectionProblem2P; + +namespace Properties +{ +NEW_TYPE_TAG(InjectionProblem2P, INHERITS_FROM(TwoP, InjectionSpatialParams)); +NEW_TYPE_TAG(InjectionCCProblem2P, INHERITS_FROM(CCModel, InjectionProblem2P)); + +// Set the grid type +#if HAVE_UG +SET_TYPE_PROP(InjectionProblem2P, Grid, Dune::UGGrid<2>); +#else +SET_TYPE_PROP(InjectionProblem2P, Grid, Dune::YaspGrid<2>); +#endif + +// Set the problem property +SET_TYPE_PROP(InjectionProblem2P, Problem, InjectionProblem2P); + +// Use the same fluid system as the 2p2c injection problem +SET_TYPE_PROP(InjectionProblem2P, FluidSystem, FluidSystems::H2ON2); + +} + +/*! + * \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. The rectangular area with the increased temperature (380 K) + * starts at (20 m, 5 m) and ends at (30 m, 35 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 5 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. + * + * To run the simulation execute the following line in shell: + * ./exercise1_2p -parameterFile exercise1.input + */ +template +class InjectionProblem2P : public ImplicitPorousMediaProblem +{ + typedef ImplicitPorousMediaProblem ParentType; + typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; + typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; + + + typedef typename GET_PROP_TYPE(TypeTag, Indices) Indices; + enum { + pressureIdx = Indices::pressureIdx, + saturationIdx = Indices::saturationIdx, + + contiNEqIdx = Indices::contiNEqIdx, + + // world dimension + dimWorld = GridView::dimensionworld + }; + + + typedef typename GET_PROP_TYPE(TypeTag, PrimaryVariables) PrimaryVariables; + typedef typename GET_PROP_TYPE(TypeTag, BoundaryTypes) BoundaryTypes; + typedef typename GET_PROP_TYPE(TypeTag, TimeManager) TimeManager; + + typedef typename GridView::template Codim<0>::Entity Element; + typedef typename GridView::Intersection Intersection; + + typedef typename GET_PROP_TYPE(TypeTag, FVElementGeometry) FVElementGeometry; + typedef typename GET_PROP_TYPE(TypeTag, FluidSystem) FluidSystem; + + typedef Dune::FieldVector GlobalPosition; + + enum { isBox = GET_PROP_VALUE(TypeTag, ImplicitIsBox) }; + +public: + /*! + * \brief The constructor + * + * \param timeManager The time manager + * \param gridView The grid view + */ + InjectionProblem2P(TimeManager &timeManager, const GridView &gridView) + : ParentType(timeManager, gridView) + { + maxDepth_ = GET_RUNTIME_PARAM(TypeTag, Scalar, Problem.MaxDepth); + + // 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 Problem parameters + */ + // \{ + + /*! + * \brief Returns the problem name + * + * This is used as a prefix for files generated by the simulation. + */ + const std::string name() const + { return "injection-2p"; } + + /*! + * \brief Returns the temperature \f$ K \f$ + */ + Scalar temperature() const + { + return 273.15 + 30; // [K] + } + + + + /*! + * \brief Returns the source term + * + * \param values Stores the source values for the conservation equations in + * \f$ [ \textnormal{unit of primary variable} / (m^\textrm{dim} \cdot s )] \f$ + * \param globalPos The global position + */ + void sourceAtPos(PrimaryVariables &values, + const GlobalPosition &globalPos) const + { + values = 0; + } + + // \} + + /*! + * \name Boundary conditions + */ + // \{ + + /*! + * \brief Specifies which kind of boundary condition should be + * used for which equation on a given boundary segment + * + * \param values Stores the value of the boundary type + * \param globalPos The global position + */ + void boundaryTypesAtPos(BoundaryTypes &values, + const GlobalPosition &globalPos) const + { + if (globalPos[0] < eps_) + values.setAllDirichlet(); + else + values.setAllNeumann(); + + } + + /*! + * \brief Evaluates the boundary conditions for a Dirichlet + * boundary segment + * + * \param values Stores the Dirichlet values for the conservation equations in + * \f$ [ \textnormal{unit of primary variable} ] \f$ + * \param globalPos The global position + */ + void dirichletAtPos(PrimaryVariables &values, const GlobalPosition &globalPos) const + { + Scalar densityW = FluidSystem::H2O::liquidDensity(temperature(), 1e5); + values[pressureIdx] = 1e5 + (maxDepth_ - globalPos[1])*densityW*9.81; + values[saturationIdx] = 0.0; + } + + /*! + * \brief Evaluate the boundary conditions for a neumann + * boundary segment. + * + * \param values Stores the Neumann values for the conservation equations in + * \f$ [ \textnormal{unit of conserved quantity} / (m^(dim-1) \cdot s )] \f$ + * \param element The finite element + * \param fvGeometry The finite volume geometry of the element + * \param intersection The intersection between element and boundary + * \param scvIdx The local index of the sub-control volume + * \param boundaryFaceIdx The index of the boundary face + * + * The \a values store the mass flux of each phase normal to the boundary. + * Negative values indicate an inflow. + */ + void neumann(PrimaryVariables &values, + const Element &element, + const FVElementGeometry &fvGeometry, + const Intersection &intersection, + int scvIdx, + int boundaryFaceIdx) const + { + values = 0; + + GlobalPosition globalPos; + if (isBox) + globalPos = element.geometry().corner(scvIdx); + else + globalPos = intersection.geometry().center(); + + if (globalPos[1] < 15 + eps_ && globalPos[1] > 7 - eps_) { + // inject air. negative values mean injection + values[contiNEqIdx] = -1e-3; // kg/(s*m^2) + } + } + + // \} + + + /*! + * \name Volume terms + */ + // \{ + + /*! + * \brief Evaluates the initial values for a control volume + * + * \param values Stores the initial values for the conservation equations in + * \f$ [ \textnormal{unit of primary variables} ] \f$ + * \param globalPos The global position + */ + void initialAtPos(PrimaryVariables &values, const GlobalPosition &globalPos) const + { + Scalar densityW = FluidSystem::H2O::liquidDensity(temperature(), 1e5); + values[pressureIdx] = 1e5 + (maxDepth_ - globalPos[1])*densityW*9.81; + values[saturationIdx] = 0.0; + } + // \} + +private: + Scalar maxDepth_; + static constexpr Scalar eps_ = 1.5e-7; +}; +} //end namespace + +#endif diff --git a/tutorial/dumux-course/injection2pspatialparams.hh b/tutorial/dumux-course/injection2pspatialparams.hh new file mode 100644 index 0000000000..a62857268a --- /dev/null +++ b/tutorial/dumux-course/injection2pspatialparams.hh @@ -0,0 +1,242 @@ +// -*- 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 Definition of the spatial parameters for the injection problem + * which uses the isothermal two-phase two-component + * fully implicit model. + */ + +#ifndef DUMUX_INJECTION_SPATIAL_PARAMS_HH +#define DUMUX_INJECTION_SPATIAL_PARAMS_HH + +#include +#include +#include + +#include + +namespace Dumux +{ + +//forward declaration +template +class InjectionSpatialParams; + +namespace Properties +{ +// The spatial parameters TypeTag +NEW_TYPE_TAG(InjectionSpatialParams); + +// Set the spatial parameters +SET_TYPE_PROP(InjectionSpatialParams, SpatialParams, InjectionSpatialParams); + +// Set the material law parameterized by absolute saturations +SET_TYPE_PROP(InjectionSpatialParams, + MaterialLaw, + EffToAbsLaw >); +} + +/*! + * \ingroup TwoPTwoCModel + * \ingroup ImplicitTestProblems + * \brief Definition of the spatial parameters for the injection problem + * which uses the isothermal two-phase two-component + * fully implicit model. + */ +template +class InjectionSpatialParams : public ImplicitSpatialParams +{ + typedef ImplicitSpatialParams ParentType; + typedef typename GET_PROP_TYPE(TypeTag, Grid) Grid; + typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; + typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; + typedef typename Grid::ctype CoordScalar; + typedef typename GET_PROP_TYPE(TypeTag, FluidSystem) FluidSystem; + + enum { + dim=GridView::dimension, + dimWorld=GridView::dimensionworld + }; + + typedef Dune::FieldVector GlobalPosition; + + typedef typename GET_PROP_TYPE(TypeTag, FVElementGeometry) FVElementGeometry; + typedef typename GridView::template Codim<0>::Entity Element; + +public: + typedef typename GET_PROP_TYPE(TypeTag, MaterialLaw) MaterialLaw; + typedef typename MaterialLaw::Params MaterialLawParams; + + /*! + * \brief The constructor + * + * \param gridView The grid view + */ + InjectionSpatialParams(const GridView &gridView) + : ParentType(gridView) + { + layerBottom_ = 22.0; + + // intrinsic permeabilities + fineK_ = 1e-13; + coarseK_ = 1e-12; + + // porosities + finePorosity_ = 0.2; + coarsePorosity_ = 0.4; + + // heat conductivity of granite + lambdaSolid_ = 2.8; + + // residual saturations + fineMaterialParams_.setSwr(0.2); + fineMaterialParams_.setSnr(0.0); + coarseMaterialParams_.setSwr(0.2); + coarseMaterialParams_.setSnr(0.0); + + // parameters for the Brooks-Corey law + fineMaterialParams_.setPe(1e4); + coarseMaterialParams_.setPe(1e4); + fineMaterialParams_.setLambda(2.0); + coarseMaterialParams_.setLambda(2.0); + } + + /*! + * \brief Returns the intrinsic permeability tensor \f$[m^2]\f$ + * + * \param element The finite element + * \param fvGeometry The finite volume geometry of the element + * \param scvIdx The local index of the sub-control volume + */ + const Scalar intrinsicPermeability(const Element &element, + const FVElementGeometry &fvGeometry, + const int scvIdx) const + { + const GlobalPosition &globalPos = fvGeometry.subContVol[scvIdx].global; + if (isFineMaterial_(globalPos)) + return fineK_; + return coarseK_; + } + + /*! + * \brief Returns the porosity \f$[-]\f$ + * + * \param element The finite element + * \param fvGeometry The finite volume geometry of the element + * \param scvIdx The local index of the sub-control volume + */ + Scalar porosity(const Element &element, + const FVElementGeometry &fvGeometry, + const int scvIdx) const + { + const GlobalPosition &globalPos = fvGeometry.subContVol[scvIdx].global; + if (isFineMaterial_(globalPos)) + return finePorosity_; + return coarsePorosity_; + } + + + /*! + * \brief Returns the parameter object for the capillary-pressure/ + * saturation material law + * + * \param element The finite element + * \param fvGeometry The finite volume geometry of the element + * \param scvIdx The local index of the sub-control volume + */ + const MaterialLawParams& materialLawParams(const Element &element, + const FVElementGeometry &fvGeometry, + const int scvIdx) const + { + const GlobalPosition &globalPos = fvGeometry.subContVol[scvIdx].global; + if (isFineMaterial_(globalPos)) + return fineMaterialParams_; + return coarseMaterialParams_; + } + + /*! + * \brief Returns the heat capacity \f$[J / (kg K)]\f$ of the rock matrix. + * + * This is only required for non-isothermal models. + * + * \param element The finite element + * \param fvGeometry The finite volume geometry + * \param scvIdx The local index of the sub-control volume + */ + Scalar solidHeatCapacity(const Element &element, + const FVElementGeometry &fvGeometry, + const int scvIdx) const + { + return 790; // specific heat capacity of granite [J / (kg K)] + } + + /*! + * \brief Returns the mass density \f$[kg / m^3]\f$ of the rock matrix. + * + * This is only required for non-isothermal models. + * + * \param element The finite element + * \param fvGeometry The finite volume geometry + * \param scvIdx The local index of the sub-control volume + */ + Scalar solidDensity(const Element &element, + const FVElementGeometry &fvGeometry, + const int scvIdx) const + { + return 2700; // density of granite [kg/m^3] + } + + /*! + * \brief Returns the thermal conductivity \f$\mathrm{[W/(m K)]}\f$ of the solid + * + * This is only required for non-isothermal models. + * + * \param element The finite element + * \param fvGeometry The finite volume geometry of the element + * \param scvIdx The local index of the sub-control volume + */ + Scalar solidThermalConductivity(const Element &element, + const FVElementGeometry &fvGeometry, + const int scvIdx) const + { + return lambdaSolid_; + } + +private: + bool isFineMaterial_(const GlobalPosition &globalPos) const + { return globalPos[dimWorld-1] > layerBottom_; } + + Scalar fineK_; + Scalar coarseK_; + Scalar layerBottom_; + + Scalar finePorosity_; + Scalar coarsePorosity_; + + Scalar lambdaSolid_; + + MaterialLawParams fineMaterialParams_; + MaterialLawParams coarseMaterialParams_; +}; + +} + +#endif -- GitLab From 52f1e8291bd772aad53be8aec635f7b7d63fd6eb Mon Sep 17 00:00:00 2001 From: Katharina Heck Date: Thu, 14 Sep 2017 15:26:37 +0200 Subject: [PATCH 02/42] [tutorial][exercise1] add finished exercise and solution for the dumux course --- tutorial/CMakeLists.txt | 1 + tutorial/dumux-course/exercise1.input | 3 + tutorial/dumux-course/injection2p2cproblem.hh | 2 +- tutorial/dumux-course/injection2pniproblem.hh | 294 ++++++++++++++++++ tutorial/dumux-course/injection2pproblem.hh | 11 +- .../dumux-course/injection2pspatialparams.hh | 53 ++-- 6 files changed, 334 insertions(+), 30 deletions(-) create mode 100644 tutorial/dumux-course/injection2pniproblem.hh diff --git a/tutorial/CMakeLists.txt b/tutorial/CMakeLists.txt index adc6d64473..36770c9491 100644 --- a/tutorial/CMakeLists.txt +++ b/tutorial/CMakeLists.txt @@ -15,3 +15,4 @@ tutorialproblem_sequential.hh tutorialspatialparams_implicit.hh tutorialspatialparams_sequential.hh DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/dumux/tutorial) +add_subdirectory(dumux-course) diff --git a/tutorial/dumux-course/exercise1.input b/tutorial/dumux-course/exercise1.input index 2e400a0bb7..a4e055be8c 100755 --- a/tutorial/dumux-course/exercise1.input +++ b/tutorial/dumux-course/exercise1.input @@ -13,3 +13,6 @@ MaxDepth = 2700.0 [Newton] WriteConvergence = 1 # write convergence behaviour to disk? +[SpatialParams] +EntryPressureFine = 4.5e4 +EntryPressureCoarse = 1e4 diff --git a/tutorial/dumux-course/injection2p2cproblem.hh b/tutorial/dumux-course/injection2p2cproblem.hh index 3ffe656288..a63bc73d1c 100644 --- a/tutorial/dumux-course/injection2p2cproblem.hh +++ b/tutorial/dumux-course/injection2p2cproblem.hh @@ -69,7 +69,7 @@ SET_BOOL_PROP(Injection2p2cProblem, UseMoles, true); * * A mixture of Nitrogen and Water vapor, which is composed according to the prevailing conditions (temperature, pressure) * enters a water-filled aquifer. This is realized with a solution-dependent Neumann boundary condition at the right boundary - * (\f$ 5m. * + *****************************************************************************/ +/*! + * \file + * + * \brief Non-isothermal gas injection problem where a gas (e.g. air) is injected into a fully + * water saturated medium. During buoyancy driven upward migration the gas + * passes a high temperature area. + */ + +#ifndef DUMUX_INJECTION_PROBLEM_2PNI_HH +#define DUMUX_INJECTION_PROBLEM_2PNI_HH + +#include +#include + +#include + +#include "injection2pspatialparams.hh" + +namespace Dumux { + +template +class InjectionProblem2PNI; + +namespace Properties +{ +NEW_TYPE_TAG(InjectionProblem2PNI, INHERITS_FROM(TwoPNI, InjectionSpatialParams)); +NEW_TYPE_TAG(InjectionCCProblem2PNI, INHERITS_FROM(CCModel, InjectionProblem2PNI)); + +// Set the grid type +SET_TYPE_PROP(InjectionProblem2PNI, Grid, Dune::YaspGrid<2>); + +// Set the problem property +SET_TYPE_PROP(InjectionProblem2PNI, Problem, InjectionProblem2PNI); + +// Use the same fluid system as the 2p2c injection problem +SET_TYPE_PROP(InjectionProblem2PNI, FluidSystem, FluidSystems::H2ON2); + +} + +/*! + * \ingroup TwoPModel + * \ingroup ImplicitTestProblems + * \brief Non-isothermal gas injection problem where a gas (e.g. air) 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. The rectangular area with the increased temperature (380 K) + * starts at (20 m, 5 m) and ends at (30 m, 35 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. + * For the energy conservation equation dirichlet boundary conditions are applied + * on all boundaries. + * + * 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, a gas saturation of zero and + * a geothermal temperature gradient of 0.03 K/m are applied. + * + * This problem uses the \ref TwoPModel and \ref NIModel model. + * + * To run the simulation execute the following line in shell: + * ./exercise1_2pni -ParameterFile exercise1.input + */ +template +class InjectionProblem2PNI : public ImplicitPorousMediaProblem +{ + typedef ImplicitPorousMediaProblem ParentType; + typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; + typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; + + + typedef typename GET_PROP_TYPE(TypeTag, Indices) Indices; + enum { + pressureIdx = Indices::pressureIdx, + saturationIdx = Indices::saturationIdx, + + contiNEqIdx = Indices::contiNEqIdx, + + /* + * dumux-course-task: + * get the temperatureIdx as the index for the primary variable temperature and the + * energyIdx as the index for the energy conservation equation for your convinience. + */ + + // world dimension + dimWorld = GridView::dimensionworld + }; + + + typedef typename GET_PROP_TYPE(TypeTag, PrimaryVariables) PrimaryVariables; + typedef typename GET_PROP_TYPE(TypeTag, BoundaryTypes) BoundaryTypes; + typedef typename GET_PROP_TYPE(TypeTag, TimeManager) TimeManager; + + typedef typename GridView::template Codim<0>::Entity Element; + typedef typename GridView::Intersection Intersection; + + typedef typename GET_PROP_TYPE(TypeTag, FVElementGeometry) FVElementGeometry; + typedef typename GET_PROP_TYPE(TypeTag, FluidSystem) FluidSystem; + + typedef Dune::FieldVector GlobalPosition; + + enum { isBox = GET_PROP_VALUE(TypeTag, ImplicitIsBox) }; + +public: + /*! + * \brief The constructor + * + * \param timeManager The time manager + * \param gridView The grid view + */ + InjectionProblem2PNI(TimeManager &timeManager, const GridView &gridView) + : ParentType(timeManager, gridView) + { + maxDepth_ = GET_RUNTIME_PARAM(TypeTag, Scalar, Problem.MaxDepth); + + // 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 Problem parameters + */ + // \{ + + /*! + * \brief Returns the problem name + * + * This is used as a prefix for files generated by the simulation. + */ + const std::string name() const + { return "injection-2pni";} + + /*! + * \brief Returns the source term + * + * \param values Stores the source values for the conservation equations in + * \f$ [ \textnormal{unit of primary variable} / (m^\textrm{dim} \cdot s )] \f$ + * \param globalPos The global position + */ + void sourceAtPos(PrimaryVariables &values, + const GlobalPosition &globalPos) const + { + values = 0; + } + + // \} + + /*! + * \name Boundary conditions + */ + // \{ + + /*! + * \brief Specifies which kind of boundary condition should be + * used for which equation on a given boundary segment + * + * \param values Stores the value of the boundary type + * \param globalPos The global position + */ + void boundaryTypesAtPos(BoundaryTypes &values, + const GlobalPosition &globalPos) const + { + if (globalPos[0] < eps_) + values.setAllDirichlet(); + else + values.setAllNeumann(); + + /*! + * dumux-course-task: + * set dirichlet conditions for the temperature index everywhere + */ + } + + /*! + * \brief Evaluates the boundary conditions for a Dirichlet + * boundary segment + * + * \param values Stores the Dirichlet values for the conservation equations in + * \f$ [ \textnormal{unit of primary variable} ] \f$ + * \param globalPos The global position + */ + void dirichletAtPos(PrimaryVariables &values, const GlobalPosition &globalPos) const + { + Scalar densityW = 1000.0; + values[pressureIdx] = 1e5 + (maxDepth_ - globalPos[1])*densityW*9.81; + values[saturationIdx] = 0.0; + /*! + * dumux-course-task: + * set a temperature gradient of 0.03 K per m beginning at 283 K here. + * Hint: you can use maxDepth_ and the globalPos similar to the pressure gradient + */ + } + + /*! + * \brief Evaluate the boundary conditions for a neumann + * boundary segment. + * + * \param values Stores the Neumann values for the conservation equations in + * \f$ [ \textnormal{unit of conserved quantity} / (m^(dim-1) \cdot s )] \f$ + * \param element The finite element + * \param fvGeometry The finite volume geometry of the element + * \param intersection The intersection between element and boundary + * \param scvIdx The local index of the sub-control volume + * \param boundaryFaceIdx The index of the boundary face + * + * The \a values store the mass flux of each phase normal to the boundary. + * Negative values indicate an inflow. + */ + void neumann(PrimaryVariables &values, + const Element &element, + const FVElementGeometry &fvGeometry, + const Intersection &intersection, + int scvIdx, + int boundaryFaceIdx) const + { + values = 0; + + GlobalPosition globalPos; + if (isBox) + globalPos = element.geometry().corner(scvIdx); + else + globalPos = intersection.geometry().center(); + + if (globalPos[1] < 15 + eps_ && globalPos[1] > 7 - eps_) { + // inject air. negative values mean injection + values[contiNEqIdx] = -1e-3; // kg/(s*m^2) + } + } + + // \} + + + /*! + * \name Volume terms + */ + // \{ + + /*! + * \brief Evaluates the initial values for a control volume + * + * \param values Stores the initial values for the conservation equations in + * \f$ [ \textnormal{unit of primary variables} ] \f$ + * \param globalPos The global position + */ + void initialAtPos(PrimaryVariables &values, const GlobalPosition &globalPos) const + { + Scalar densityW = 1000.0; + values[pressureIdx] = 1e5 + (maxDepth_ - globalPos[1])*densityW*9.81; + values[saturationIdx] = 0.0; + + /*! + * dumux-course-task: + * set a temperature gradient of 0.03 K per m beginning at 283 K here. + * Hint: you can use maxDepth_ and the globalPos similar to the pressure gradient + * use globalPos[0] and globalpos[1] to implement the high temperature lens with 380 K + */ + } + + +private: + Scalar maxDepth_; + static constexpr Scalar eps_ = 1.5e-7; + std::string name_; +}; +} //end namespace + +#endif diff --git a/tutorial/dumux-course/injection2pproblem.hh b/tutorial/dumux-course/injection2pproblem.hh index eba0e274cf..fbf085c328 100644 --- a/tutorial/dumux-course/injection2pproblem.hh +++ b/tutorial/dumux-course/injection2pproblem.hh @@ -45,11 +45,7 @@ NEW_TYPE_TAG(InjectionProblem2P, INHERITS_FROM(TwoP, InjectionSpatialParams)); NEW_TYPE_TAG(InjectionCCProblem2P, INHERITS_FROM(CCModel, InjectionProblem2P)); // Set the grid type -#if HAVE_UG -SET_TYPE_PROP(InjectionProblem2P, Grid, Dune::UGGrid<2>); -#else SET_TYPE_PROP(InjectionProblem2P, Grid, Dune::YaspGrid<2>); -#endif // Set the problem property SET_TYPE_PROP(InjectionProblem2P, Problem, InjectionProblem2P); @@ -66,14 +62,13 @@ SET_TYPE_PROP(InjectionProblem2P, FluidSystem, FluidSystems::H2ON2./exercise1_2p -parameterFile exercise1.input + * ./exercise1_2p -ParameterFile exercise1.input */ template class InjectionProblem2P : public ImplicitPorousMediaProblem diff --git a/tutorial/dumux-course/injection2pspatialparams.hh b/tutorial/dumux-course/injection2pspatialparams.hh index a62857268a..fc85aa4c21 100644 --- a/tutorial/dumux-course/injection2pspatialparams.hh +++ b/tutorial/dumux-course/injection2pspatialparams.hh @@ -93,7 +93,7 @@ public: InjectionSpatialParams(const GridView &gridView) : ParentType(gridView) { - layerBottom_ = 22.0; + layerBottom_ = 25.0; // intrinsic permeabilities fineK_ = 1e-13; @@ -103,6 +103,10 @@ public: finePorosity_ = 0.2; coarsePorosity_ = 0.4; + //materialLawParams + fineEntryPressure_ = GET_RUNTIME_PARAM(TypeTag, Scalar, SpatialParams.EntryPressureFine); + coarseEntryPressure_ = GET_RUNTIME_PARAM(TypeTag, Scalar, SpatialParams.EntryPressureCoarse); + // heat conductivity of granite lambdaSolid_ = 2.8; @@ -113,8 +117,8 @@ public: coarseMaterialParams_.setSnr(0.0); // parameters for the Brooks-Corey law - fineMaterialParams_.setPe(1e4); - coarseMaterialParams_.setPe(1e4); + fineMaterialParams_.setPe(fineEntryPressure_); + coarseMaterialParams_.setPe(coarseEntryPressure_); fineMaterialParams_.setLambda(2.0); coarseMaterialParams_.setLambda(2.0); } @@ -172,6 +176,10 @@ public: return coarseMaterialParams_; } + /*! + * These parameters are only needed for nonisothermal models. Comment them in if you want to implement the 2pni model. + */ + /*! * \brief Returns the heat capacity \f$[J / (kg K)]\f$ of the rock matrix. * @@ -181,12 +189,12 @@ public: * \param fvGeometry The finite volume geometry * \param scvIdx The local index of the sub-control volume */ - Scalar solidHeatCapacity(const Element &element, - const FVElementGeometry &fvGeometry, - const int scvIdx) const - { - return 790; // specific heat capacity of granite [J / (kg K)] - } +// Scalar solidHeatCapacity(const Element &element, +// const FVElementGeometry &fvGeometry, +// const int scvIdx) const +// { +// return 790; // specific heat capacity of granite [J / (kg K)] +// } /*! * \brief Returns the mass density \f$[kg / m^3]\f$ of the rock matrix. @@ -197,12 +205,12 @@ public: * \param fvGeometry The finite volume geometry * \param scvIdx The local index of the sub-control volume */ - Scalar solidDensity(const Element &element, - const FVElementGeometry &fvGeometry, - const int scvIdx) const - { - return 2700; // density of granite [kg/m^3] - } +// Scalar solidDensity(const Element &element, +// const FVElementGeometry &fvGeometry, +// const int scvIdx) const +// { +// return 2700; // density of granite [kg/m^3] +// } /*! * \brief Returns the thermal conductivity \f$\mathrm{[W/(m K)]}\f$ of the solid @@ -213,12 +221,12 @@ public: * \param fvGeometry The finite volume geometry of the element * \param scvIdx The local index of the sub-control volume */ - Scalar solidThermalConductivity(const Element &element, - const FVElementGeometry &fvGeometry, - const int scvIdx) const - { - return lambdaSolid_; - } +// Scalar solidThermalConductivity(const Element &element, +// const FVElementGeometry &fvGeometry, +// const int scvIdx) const +// { +// return lambdaSolid_; +// } private: bool isFineMaterial_(const GlobalPosition &globalPos) const @@ -233,6 +241,9 @@ private: Scalar lambdaSolid_; + Scalar fineEntryPressure_; + Scalar coarseEntryPressure_; + MaterialLawParams fineMaterialParams_; MaterialLawParams coarseMaterialParams_; }; -- GitLab From 9d553d23847c4183be602307487aff0c4bc287e1 Mon Sep 17 00:00:00 2001 From: Katharina Heck Date: Thu, 14 Sep 2017 15:33:31 +0200 Subject: [PATCH 03/42] [fix][tutorial] add forgotten solution and forgotten task for the course --- tutorial/dumux-course/injection2pniproblem.hh | 6 +- .../dumux-course/solution/exercise1_2pni.cc | 64 ++++ .../solution/injection2pniproblem.hh | 285 ++++++++++++++++++ 3 files changed, 354 insertions(+), 1 deletion(-) create mode 100644 tutorial/dumux-course/solution/exercise1_2pni.cc create mode 100644 tutorial/dumux-course/solution/injection2pniproblem.hh diff --git a/tutorial/dumux-course/injection2pniproblem.hh b/tutorial/dumux-course/injection2pniproblem.hh index d9f8b011a5..eb8a962478 100644 --- a/tutorial/dumux-course/injection2pniproblem.hh +++ b/tutorial/dumux-course/injection2pniproblem.hh @@ -41,7 +41,11 @@ class InjectionProblem2PNI; namespace Properties { -NEW_TYPE_TAG(InjectionProblem2PNI, INHERITS_FROM(TwoPNI, InjectionSpatialParams)); + /*! +* dumux-course-task: +* inherit from the TwoPNI model instead of TwoP here +*/ +NEW_TYPE_TAG(InjectionProblem2PNI, INHERITS_FROM(TwoP, InjectionSpatialParams)); NEW_TYPE_TAG(InjectionCCProblem2PNI, INHERITS_FROM(CCModel, InjectionProblem2PNI)); // Set the grid type diff --git a/tutorial/dumux-course/solution/exercise1_2pni.cc b/tutorial/dumux-course/solution/exercise1_2pni.cc new file mode 100644 index 0000000000..69f233e059 --- /dev/null +++ b/tutorial/dumux-course/solution/exercise1_2pni.cc @@ -0,0 +1,64 @@ +// -*- 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 DOC ME! + */ +#include "config.h" +#include "injection2pniproblem.hh" +#include + +/*! + * \brief Provides an interface for customizing error messages associated with + * reading in parameters. + * + * \param progName The name of the program, that was tried to be started. + * \param errorMsg The error message that was issued by the start function. + * Comprises the thing that went wrong and a general help message. + */ +void usage(const char *progName, const std::string &errorMsg) +{ + if (errorMsg.size() > 0) { + std::string errorMessageOut = "\nUsage: "; + errorMessageOut += progName; + errorMessageOut += " [options]\n"; + errorMessageOut += errorMsg; + errorMessageOut += "\n\nThe list of mandatory options for this program is:\n" + "\t-TimeManager.TEnd End of the simulation [s] \n" + "\t-TimeManager.DtInitial Initial timestep size [s] \n" + "\t-Grid.File Name of the file containing the grid \n" + "\t definition in DGF format\n" + "\t-SpatialParams.LensLowerLeft coordinates of the lower left corner of the lens [m] \n" + "\t-SpatialParams.LensUpperRight coordinates of the upper right corner of the lens [m] \n" + "\t-Problem.Name String for naming of the output files \n" + "\n"; + std::cout << errorMessageOut + << "\n"; + } +} + +//////////////////////// +// the main function +//////////////////////// +int main(int argc, char** argv) +{ + typedef TTAG(InjectionCCProblem2PNI) ProblemTypeTag; + return Dumux::start(argc, argv, usage); +} diff --git a/tutorial/dumux-course/solution/injection2pniproblem.hh b/tutorial/dumux-course/solution/injection2pniproblem.hh new file mode 100644 index 0000000000..7bba02cae5 --- /dev/null +++ b/tutorial/dumux-course/solution/injection2pniproblem.hh @@ -0,0 +1,285 @@ +// -*- 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 Non-isothermal gas injection problem where a gas (e.g. air) is injected into a fully + * water saturated medium. During buoyancy driven upward migration the gas + * passes a high temperature area. + */ + +#ifndef DUMUX_INJECTION_PROBLEM_2PNI_HH +#define DUMUX_INJECTION_PROBLEM_2PNI_HH + +#include +#include + +#include + +#include "injection2pspatialparams.hh" + +namespace Dumux { + +template +class InjectionProblem2PNI; + +namespace Properties +{ +NEW_TYPE_TAG(InjectionProblem2PNI, INHERITS_FROM(TwoPNI, InjectionSpatialParams)); +NEW_TYPE_TAG(InjectionCCProblem2PNI, INHERITS_FROM(CCModel, InjectionProblem2PNI)); + +// Set the grid type +SET_TYPE_PROP(InjectionProblem2PNI, Grid, Dune::YaspGrid<2>); + +// Set the problem property +SET_TYPE_PROP(InjectionProblem2PNI, Problem, InjectionProblem2PNI); + +// Use the same fluid system as the 2p2c injection problem +SET_TYPE_PROP(InjectionProblem2PNI, FluidSystem, FluidSystems::H2ON2); + +} + +/*! + * \ingroup TwoPModel + * \ingroup ImplicitTestProblems + * \brief Non-isothermal gas injection problem where a gas (e.g. air) 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. The rectangular area with the increased temperature (380 K) + * starts at (20 m, 5 m) and ends at (30 m, 35 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. + * For the energy conservation equation dirichlet boundary conditions are applied + * on all boundaries. + * + * 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, a gas saturation of zero and + * a geothermal temperature gradient of 0.03 K/m are applied. + * + * This problem uses the \ref TwoPModel and \ref NIModel model. + * + * To run the simulation execute the following line in shell: + * ./exercise1_2pni -ParameterFile exercise1.input + */ +template +class InjectionProblem2PNI : public ImplicitPorousMediaProblem +{ + typedef ImplicitPorousMediaProblem ParentType; + typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; + typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; + + + typedef typename GET_PROP_TYPE(TypeTag, Indices) Indices; + enum { + pressureIdx = Indices::pressureIdx, + saturationIdx = Indices::saturationIdx, + + contiNEqIdx = Indices::contiNEqIdx, + + temperatureIdx = Indices::temperatureIdx, + energyEqIdx = Indices::energyEqIdx, + + // world dimension + dimWorld = GridView::dimensionworld + }; + + + typedef typename GET_PROP_TYPE(TypeTag, PrimaryVariables) PrimaryVariables; + typedef typename GET_PROP_TYPE(TypeTag, BoundaryTypes) BoundaryTypes; + typedef typename GET_PROP_TYPE(TypeTag, TimeManager) TimeManager; + + typedef typename GridView::template Codim<0>::Entity Element; + typedef typename GridView::Intersection Intersection; + + typedef typename GET_PROP_TYPE(TypeTag, FVElementGeometry) FVElementGeometry; + typedef typename GET_PROP_TYPE(TypeTag, FluidSystem) FluidSystem; + + typedef Dune::FieldVector GlobalPosition; + + enum { isBox = GET_PROP_VALUE(TypeTag, ImplicitIsBox) }; + +public: + /*! + * \brief The constructor + * + * \param timeManager The time manager + * \param gridView The grid view + */ + InjectionProblem2PNI(TimeManager &timeManager, const GridView &gridView) + : ParentType(timeManager, gridView) + { + maxDepth_ = GET_RUNTIME_PARAM(TypeTag, Scalar, Problem.MaxDepth); + + // 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 Problem parameters + */ + // \{ + + /*! + * \brief Returns the problem name + * + * This is used as a prefix for files generated by the simulation. + */ + const std::string name() const + { return "injection-2pni";} + + /*! + * \brief Returns the source term + * + * \param values Stores the source values for the conservation equations in + * \f$ [ \textnormal{unit of primary variable} / (m^\textrm{dim} \cdot s )] \f$ + * \param globalPos The global position + */ + void sourceAtPos(PrimaryVariables &values, + const GlobalPosition &globalPos) const + { + values = 0; + } + + // \} + + /*! + * \name Boundary conditions + */ + // \{ + + /*! + * \brief Specifies which kind of boundary condition should be + * used for which equation on a given boundary segment + * + * \param values Stores the value of the boundary type + * \param globalPos The global position + */ + void boundaryTypesAtPos(BoundaryTypes &values, + const GlobalPosition &globalPos) const + { + if (globalPos[0] < eps_) + values.setAllDirichlet(); + else + values.setAllNeumann(); + + + // set a dirichlet value for the temperature, use the energy + // equation to set the value + values.setDirichlet(temperatureIdx); + } + + /*! + * \brief Evaluates the boundary conditions for a Dirichlet + * boundary segment + * + * \param values Stores the Dirichlet values for the conservation equations in + * \f$ [ \textnormal{unit of primary variable} ] \f$ + * \param globalPos The global position + */ + void dirichletAtPos(PrimaryVariables &values, const GlobalPosition &globalPos) const + { + Scalar densityW = 1000.0; + values[pressureIdx] = 1e5 + (maxDepth_ - globalPos[1])*densityW*9.81; + values[saturationIdx] = 0.0; + values[temperatureIdx] = 283.0 + (maxDepth_ - globalPos[1])*0.03; + + } + + /*! + * \brief Evaluate the boundary conditions for a neumann + * boundary segment. + * + * \param values Stores the Neumann values for the conservation equations in + * \f$ [ \textnormal{unit of conserved quantity} / (m^(dim-1) \cdot s )] \f$ + * \param element The finite element + * \param fvGeometry The finite volume geometry of the element + * \param intersection The intersection between element and boundary + * \param scvIdx The local index of the sub-control volume + * \param boundaryFaceIdx The index of the boundary face + * + * The \a values store the mass flux of each phase normal to the boundary. + * Negative values indicate an inflow. + */ + void neumann(PrimaryVariables &values, + const Element &element, + const FVElementGeometry &fvGeometry, + const Intersection &intersection, + int scvIdx, + int boundaryFaceIdx) const + { + values = 0; + + GlobalPosition globalPos; + if (isBox) + globalPos = element.geometry().corner(scvIdx); + else + globalPos = intersection.geometry().center(); + + if (globalPos[1] < 15 + eps_ && globalPos[1] > 7 - eps_) { + // inject air. negative values mean injection + values[contiNEqIdx] = -1e-3; // kg/(s*m^2) + } + } + + // \} + + + /*! + * \name Volume terms + */ + // \{ + + /*! + * \brief Evaluates the initial values for a control volume + * + * \param values Stores the initial values for the conservation equations in + * \f$ [ \textnormal{unit of primary variables} ] \f$ + * \param globalPos The global position + */ + void initialAtPos(PrimaryVariables &values, const GlobalPosition &globalPos) const + { + Scalar densityW = 1000.0; + values[pressureIdx] = 1e5 + (maxDepth_ - globalPos[1])*densityW*9.81; + values[saturationIdx] = 0.0; + + values[temperatureIdx] = 283.0 + (maxDepth_ - globalPos[1])*0.03; + if (globalPos[0] > 20 - eps_ && globalPos[0] < 30 + eps_ && globalPos[1] > 5 - eps_ && globalPos[1] < 35 + eps_) + values[temperatureIdx] = 380; + } + + +private: + Scalar maxDepth_; + static constexpr Scalar eps_ = 1.5e-7; + std::string name_; +}; +} //end namespace + +#endif -- GitLab From cb692be937230931849840ab9396491f51788298 Mon Sep 17 00:00:00 2001 From: Katharina Heck Date: Tue, 19 Sep 2017 08:56:36 +0200 Subject: [PATCH 04/42] [exercise1] add readme and rename folders to new structure --- tutorial/CMakeLists.txt | 2 +- tutorial/doc/dumux-course1.png | Bin 0 -> 18444 bytes tutorial/doc/dumux-course2.png | Bin 0 -> 44121 bytes tutorial/{dumux-course => ex1}/CMakeLists.txt | 0 tutorial/ex1/README.md | Bin 0 -> 6650 bytes tutorial/{dumux-course => ex1}/exercise1.input | 0 tutorial/{dumux-course => ex1}/exercise1_2p.cc | 0 .../{dumux-course => ex1}/exercise1_2p2c.cc | 0 .../injection2p2cproblem.hh | 0 .../injection2pniproblem.hh | 0 .../{dumux-course => ex1}/injection2pproblem.hh | 0 .../injection2pspatialparams.hh | 0 .../solution => solution/ex1}/exercise1_2pni.cc | 0 .../ex1}/injection2pniproblem.hh | 0 14 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 tutorial/doc/dumux-course1.png create mode 100644 tutorial/doc/dumux-course2.png rename tutorial/{dumux-course => ex1}/CMakeLists.txt (100%) create mode 100644 tutorial/ex1/README.md rename tutorial/{dumux-course => ex1}/exercise1.input (100%) rename tutorial/{dumux-course => ex1}/exercise1_2p.cc (100%) rename tutorial/{dumux-course => ex1}/exercise1_2p2c.cc (100%) rename tutorial/{dumux-course => ex1}/injection2p2cproblem.hh (100%) rename tutorial/{dumux-course => ex1}/injection2pniproblem.hh (100%) rename tutorial/{dumux-course => ex1}/injection2pproblem.hh (100%) rename tutorial/{dumux-course => ex1}/injection2pspatialparams.hh (100%) rename tutorial/{dumux-course/solution => solution/ex1}/exercise1_2pni.cc (100%) rename tutorial/{dumux-course/solution => solution/ex1}/injection2pniproblem.hh (100%) diff --git a/tutorial/CMakeLists.txt b/tutorial/CMakeLists.txt index 36770c9491..f73220e201 100644 --- a/tutorial/CMakeLists.txt +++ b/tutorial/CMakeLists.txt @@ -15,4 +15,4 @@ tutorialproblem_sequential.hh tutorialspatialparams_implicit.hh tutorialspatialparams_sequential.hh DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/dumux/tutorial) -add_subdirectory(dumux-course) +add_subdirectory(ex1) diff --git a/tutorial/doc/dumux-course1.png b/tutorial/doc/dumux-course1.png new file mode 100644 index 0000000000000000000000000000000000000000..250574f2f795596c658c68f32834b897cb27dbab GIT binary patch literal 18444 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 literal 0 HcmV?d00001 diff --git a/tutorial/doc/dumux-course2.png b/tutorial/doc/dumux-course2.png new file mode 100644 index 0000000000000000000000000000000000000000..938ba158eb97e83d1ae80145161b94d2ab6137cf GIT binary patch literal 44121 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 literal 0 HcmV?d00001 diff --git a/tutorial/dumux-course/CMakeLists.txt b/tutorial/ex1/CMakeLists.txt similarity index 100% rename from tutorial/dumux-course/CMakeLists.txt rename to tutorial/ex1/CMakeLists.txt diff --git a/tutorial/ex1/README.md b/tutorial/ex1/README.md new file mode 100644 index 0000000000000000000000000000000000000000..152940f326c8c041ee433cb33aff09191393ec8b GIT binary patch literal 6650 zcmds*UvFDQ5XJWyiDzD~DjsO4oyKVjs#+wV1yx0DMf<>CQO9u-w{~J;r)l|Ae4IYy zvjFF}CzHL`zE08yctDo_-1YA4%$b=pv-|g7_tSBj==~;j(%0!wzmC!@4bz=er3V@v z>Uoexd8|qs>BICvy7!(h*6@BRS%+ymjU{y=`Rp^-zQ<{r|L^Gc>Q_iv)5^!Gr%$xv z^B}#Hq=94&)6UsQmHHaz^LNP~rCt4Zr01zVhv~IOuyrO~-fDEFdGl;L-JKJy+>w>gs({_*H4^-4CZ*@1CEor%&|zr_+zFZM}PO zdR;TH5bK_6*P*@_b+^5T$cH!iHgHvZeu z+=--N2`fhFk38<(ZcDP|zR~xsv!|l#L&>RxJ(gQDd}6!j(&11~V@ZE2nMBqNJ@@sV z=%1ZD2IBU@G(S)D**}XCBpv9v5>_9lU(yq;8>YQ1VM8O=v$TWkb)?$v@HF37mDbDB zY*$3uU12fNZlE%dtb6I2Fq`W&)ySQ+uGe1nMpvIF8tW>C4)nXD-^3Gh(e_B+-E8l= zK1;?Ci&NQX-8AmRai>?MwQ)bm?cg*tLEp-)s7^oHd8iv%a>IJrg;-AswdD zZ%=j*)g!GS3b3n}Bj}n|f05%53>NeMPHUD1TF%RU&Mj;vkBBlNpv2lpx;t0VoZPEh zYRsB86|{)5uqAS3QAaomnZ(doXxUEoM+?Uz98h=&Pga`WKfSzcbUDIJIE`M1;Rxty7u%h`p)zM zH6kgpjckU;&Ayc+jx~n}AX39yyV3%d3|#}U`fPHs&WM2zKF4D7syVuzpCQwzM*fdm zHHL}Ey@@_A*SkdEn!JxUzLg&29-K!0?n*agjr9iYHl&Fz;$}^+kocX(2IuGyQRo|% z>}H8Z`E9n_ay<*)awQ2=+hWx@RcHOe#UUU4n|?8d%{aa&io3F6uvA}~>)8c_h|H_* zw_N?utSPsvSlwUR``@sV`2TM$Wyh;nJInbB^T8xDts&!xMdFDkIG&7!HK~)u8~C*y z=cb$@g*w!Rc~c8yPQ?MRNO-M9n$3eOL;o}LjjU=?Ecl_Z8X&hN0c z@Wg6u0w?;GL&-vmI;#^gaQQfomfkabO&>cH8<)NX_S(!oDd>j2#f$ARS7*Mm+P-l$ zdM*8^8|J)4mLQ7Utx>7wieu^_K43m}@XOI$(5Y(`amc^a!^NJi>|gv9u}2Qob**E! z*az4eYgWzzWaeSEkKCm5jA(z6cn#90dNKBMdX}>`a`>qphIGDl$qJ$z`Bc|R-CBK>H48oQ;H~Wa?}au#po+38BBstUb$>rsE{1R7G_`!5 z@tFXx1nQCT7wrT?EXPwsdieS1QjLqxqqE|Kc9nQSgU3PB*CEHf zi|fxS4&>w#T=t`EIL;ctQRY4H3Wg<5sAXhtGhSA80L2dcNJfUNCQH}nMGR9VPjY;6 z4x_jC>7s6PQ%YeHG$doX>GrvGUrP7-8Mqzq#mEZ2FS3Kb7qh|LAbn;?ZfaN0*V~uI z0@2hF(y)^;<6P_B0krWOXcBFlP3xzd#h7`b|B3X1ezB(Amq>5Qbaz2c!5Zd-CNoSk z^Orn|OuH;n>U}xZn!BjEL-i=+S1=F%z;DEnvu$7B$`+<>qW&uZ!BXU?ryk0^63>V z$ylEeh#BsZ$o#MJ8qTF?NtGo6d4>_qKR(yq*Aq8*`xy(^vTdd{ZJzu<&Nnh-Th#8- zgOGc~T-&TY?b*-T1on;v--B&x`+C&>*w9q54x5hLdS8 zeXjlo`EjEbm^~CeM#q`ch6DX?_^zDOS81_qrQ-zcOMY=50FPblt9s;{alz02#Ix3! zc;=q%hUA~*+{3e#-ro5lpBS@E;R9Ze#5xgC#u4<07Uv5UjeW_l*cEiRC#uq2y}1wM zds8Fmvvu}NG%cxR7M7T`cJlZ#`?~XJW(H5o z6`^TE>Am7qTkj9z*5#!#4EAun^7rTaL4_67F=&Xzw>=K=n`xG)Mc+vWolXYkoeZ|EQ({@kfy#EJy1#nsb literal 0 HcmV?d00001 diff --git a/tutorial/dumux-course/exercise1.input b/tutorial/ex1/exercise1.input similarity index 100% rename from tutorial/dumux-course/exercise1.input rename to tutorial/ex1/exercise1.input diff --git a/tutorial/dumux-course/exercise1_2p.cc b/tutorial/ex1/exercise1_2p.cc similarity index 100% rename from tutorial/dumux-course/exercise1_2p.cc rename to tutorial/ex1/exercise1_2p.cc diff --git a/tutorial/dumux-course/exercise1_2p2c.cc b/tutorial/ex1/exercise1_2p2c.cc similarity index 100% rename from tutorial/dumux-course/exercise1_2p2c.cc rename to tutorial/ex1/exercise1_2p2c.cc diff --git a/tutorial/dumux-course/injection2p2cproblem.hh b/tutorial/ex1/injection2p2cproblem.hh similarity index 100% rename from tutorial/dumux-course/injection2p2cproblem.hh rename to tutorial/ex1/injection2p2cproblem.hh diff --git a/tutorial/dumux-course/injection2pniproblem.hh b/tutorial/ex1/injection2pniproblem.hh similarity index 100% rename from tutorial/dumux-course/injection2pniproblem.hh rename to tutorial/ex1/injection2pniproblem.hh diff --git a/tutorial/dumux-course/injection2pproblem.hh b/tutorial/ex1/injection2pproblem.hh similarity index 100% rename from tutorial/dumux-course/injection2pproblem.hh rename to tutorial/ex1/injection2pproblem.hh diff --git a/tutorial/dumux-course/injection2pspatialparams.hh b/tutorial/ex1/injection2pspatialparams.hh similarity index 100% rename from tutorial/dumux-course/injection2pspatialparams.hh rename to tutorial/ex1/injection2pspatialparams.hh diff --git a/tutorial/dumux-course/solution/exercise1_2pni.cc b/tutorial/solution/ex1/exercise1_2pni.cc similarity index 100% rename from tutorial/dumux-course/solution/exercise1_2pni.cc rename to tutorial/solution/ex1/exercise1_2pni.cc diff --git a/tutorial/dumux-course/solution/injection2pniproblem.hh b/tutorial/solution/ex1/injection2pniproblem.hh similarity index 100% rename from tutorial/dumux-course/solution/injection2pniproblem.hh rename to tutorial/solution/ex1/injection2pniproblem.hh -- GitLab From 410c7710235069584d09eb1149a31e1923571ccf Mon Sep 17 00:00:00 2001 From: Katharina Heck Date: Tue, 19 Sep 2017 09:04:56 +0200 Subject: [PATCH 05/42] [fix] rename pictures --- tutorial/doc/dumux-course1.png | Bin 18444 -> 0 bytes ...ourse2.png => exercise1_nonisothermal.png} | Bin tutorial/doc/exercise1_setup.png | Bin 0 -> 58149 bytes tutorial/ex1/README.md | Bin 6650 -> 6674 bytes 4 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 tutorial/doc/dumux-course1.png rename tutorial/doc/{dumux-course2.png => exercise1_nonisothermal.png} (100%) create mode 100644 tutorial/doc/exercise1_setup.png diff --git a/tutorial/doc/dumux-course1.png b/tutorial/doc/dumux-course1.png deleted file mode 100644 index 250574f2f795596c658c68f32834b897cb27dbab..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 18444 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 diff --git a/tutorial/doc/dumux-course2.png b/tutorial/doc/exercise1_nonisothermal.png similarity index 100% rename from tutorial/doc/dumux-course2.png rename to tutorial/doc/exercise1_nonisothermal.png diff --git a/tutorial/doc/exercise1_setup.png b/tutorial/doc/exercise1_setup.png new file mode 100644 index 0000000000000000000000000000000000000000..db9c1b4acdfe9368781cd7593b0def3963146844 GIT binary patch literal 58149 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 delta 29 icmbPa^2>O`HRj1i!V-*zn?Exf3xk Date: Tue, 19 Sep 2017 09:31:42 +0200 Subject: [PATCH 06/42] [exercise1] cleanup --- tutorial/ex1/README.md | Bin 6674 -> 6674 bytes tutorial/ex1/injection2pniproblem.hh | 8 ++++---- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tutorial/ex1/README.md b/tutorial/ex1/README.md index e1e5143578bbca51ec43b869a3cb4b7977f31a9b..6ec5354395c2db5e43f9f00046643dc0e0f4da41 100644 GIT binary patch delta 77 zcmbPaGRb5^2_wG>LpDP?gFZtpgBC+EgUaS^MrB6f1cn#}f1pq*P%4o@fx(a=Ve(!k Pdkk?ShJ?-B%HC7 delta 77 zcmbPaGRb5^38T2_jfgv@H$v{{GiWfF-iW#*u4H;6;g06!W=3U3{ul;-hFpeJhIEER V1_cJg$vc_s(Zq~4b2GDx0|4$g6`lY9 diff --git a/tutorial/ex1/injection2pniproblem.hh b/tutorial/ex1/injection2pniproblem.hh index eb8a962478..6a964f537f 100644 --- a/tutorial/ex1/injection2pniproblem.hh +++ b/tutorial/ex1/injection2pniproblem.hh @@ -42,7 +42,7 @@ class InjectionProblem2PNI; namespace Properties { /*! -* dumux-course-task: +* TODO:dumux-course-task: * inherit from the TwoPNI model instead of TwoP here */ NEW_TYPE_TAG(InjectionProblem2PNI, INHERITS_FROM(TwoP, InjectionSpatialParams)); @@ -103,7 +103,7 @@ class InjectionProblem2PNI : public ImplicitPorousMediaProblem contiNEqIdx = Indices::contiNEqIdx, /* - * dumux-course-task: + * TODO:dumux-course-task: * get the temperatureIdx as the index for the primary variable temperature and the * energyIdx as the index for the energy conservation equation for your convinience. */ @@ -216,7 +216,7 @@ public: values[pressureIdx] = 1e5 + (maxDepth_ - globalPos[1])*densityW*9.81; values[saturationIdx] = 0.0; /*! - * dumux-course-task: + * TODO:dumux-course-task: * set a temperature gradient of 0.03 K per m beginning at 283 K here. * Hint: you can use maxDepth_ and the globalPos similar to the pressure gradient */ @@ -280,7 +280,7 @@ public: values[saturationIdx] = 0.0; /*! - * dumux-course-task: + * TODO:dumux-course-task: * set a temperature gradient of 0.03 K per m beginning at 283 K here. * Hint: you can use maxDepth_ and the globalPos similar to the pressure gradient * use globalPos[0] and globalpos[1] to implement the high temperature lens with 380 K -- GitLab From 6c2ca5dd000599f793f89fe5e3fc69ef9c9d8b73 Mon Sep 17 00:00:00 2001 From: Timo Koch Date: Wed, 20 Sep 2017 18:02:05 +0200 Subject: [PATCH 07/42] [ex1] Improve readme --- tutorial/ex1/README.md | Bin 6674 -> 4714 bytes .../exercise1_nonisothermal.png | Bin .../{doc => extradoc}/exercise1_setup.png | Bin 3 files changed, 0 insertions(+), 0 deletions(-) rename tutorial/{doc => extradoc}/exercise1_nonisothermal.png (100%) rename tutorial/{doc => extradoc}/exercise1_setup.png (100%) diff --git a/tutorial/ex1/README.md b/tutorial/ex1/README.md index 6ec5354395c2db5e43f9f00046643dc0e0f4da41..35fac0962e1a266327bb44f7e55c847114932e37 100644 GIT binary patch literal 4714 zcmcIo+iu**5q;-Z6eI(Yyb|YPd$UmN1r%9p2(d1Z$4C}QK(@%9nO>1>F1uT!$wR(9 zr@DC?U6Q957Q`7=S67`nb<;kbKguRkM$-O_4nDg}_czM4Ym7XMqWyikY4lwoOES_P zyE=-l=A;a%>NlBLnd5;3{{QaOQZ`gK@=olmqpb7#=6{?{siZqu=nc%0RLBQez>J(Mj^w%& zu*#@^Nw)MymVKo6_!ZNIg>RKn#u~oVZZs8QD;sk}f=ZoBHV4MnvMHs2-=r%^2XE4U zT$gesXqLV?^cM-j7O0X>V<9ZB8bWm9nwgnAlb7*jQ)nN;Edk zLI{lr-V1Nh3CsQW(HDfjr)bVv_4@BHOsl5`@Opab2zU0B~;CpZ4a{ z>E7h$Hh!`ejjC22obFH*y`?MhpjHgO)d4uwAf~$6QtFKvUFU5JtVp9M=_xZyD3_uz zA+QW*9q3|C04P2m*J}Z4sj^fiQw(S;KnF=Oual&MbCAt+=`jF1M6oMA&u}0n5MxVs z8mxlnw@2djdQkJ45ggf9%$R2*L&j$8c=1HR$c%aR z+z_)C4X{fRQwxiPBBTiTgB&vyJOmaa9j%y`G9!n2J*ujm9gg-e#{LCz#z%Y}(;3)} zP$TBdqsCQLc;@hB&T`G++&o*0YSm}vol`}AoOk&drD=L6%sR?)3a_$K+{+m}l)>=iU#_HvEhVf>*98Q=`WCmyI;8 zu)X?tRM5t{1A@`+Yvgb5V=KU(dXV1%WJZs14PhCA8$}nDzkG<-2!l3QKEX0{sikUL z%2F37_pH#sdK9LJ%~q9){{Afx=!W@Y{u!NDw%OjmHRBrji$e4GL^Jt*_xm#~&|cd& z-tHmbKWv)RXwrH=&zWkUg zoSz>6Bo7m?V5er_3Sg7{@I%CsWGYqH((@&X{wgt0RN#@u7(l*JnUTTM5r^WnG9&Mrk;a9;Krr{AoCo(%qIe+$;f{;4)rg z=xBQ)nomO++TTe;^p-kxEXw{{80IG{Jok*~fNf6s0g)?ac^YT6P}3p zDY~0x5SlJ$JkbnpKV8AdBVWA!TMi?fE7Ynsfj`9bt(`#-0D-*UjIx{#xCr4}T^%cf zfeX_vn&n_PR)n{#fQPVfILmw&1VxGh;H7<;M#HEScXIYJ)AhFRff(6J{;(tKdp@We z`rK}>!8rS&rd7?LlN6qbUKxn72_0T852$ zZ>55hV+Et*F+e%ZxsE)66C_H{F40H7@&*#yN9)lLdCvZ`Wta@4@r8xkZIru8CU~7# zY3u=KG)(J@Wp6X`Wc=^j_4nJe^KUPT0=vT&ss(i7Qcx57Q?o^#gb{7I4}F4(E}KR- ze8NY<4*~mR*4h;qUzn`qhmXj=dC5514?~K1f`+%kckCaZl5m%9Jfv0%^C5%K4T(&= z>sp3P;*st3X!^B}OPQx#7t>c_7d8i@QC`q2mabq#O0+F3j1{f1adNFLYplfh@_BCX z5?RFbRqK1-!TZxF^%e;VjD2{~*3dT=*PpLXD6D>Ay*jqS+;;&2A%;$c?uG@tgC1=U zy{f>Ho1a98f0F!JyDAr$5^z(lxH6d&fc9B6Dq9!G(c$}kwy?6q2Fsf|8Y-{pSlUKk zp-|+C-9#Q>JAX%inUsF85WFQdesvkkLu~#Nq)=SgqKgVM*O`28N(hzc_Axa&Di*EZ9Jj*ls;nV|48qqNAv-|xBUF!@CbbkXkY*V z9r(`>!N9R4@ZsH0Q}4t7YkNl@0kAtOJSyx^WL{k58MY^N*mDguz#m`GK*pfFu+|g` z<2#oa{P-%)QE?c%9+cg-J2f{xQSc139XS4cNPD&og|73PLwfq16e*Ips--^ib}i9w F{sV9LX$AlQ literal 6674 zcmds*QEyX65QX=-Qvbsh;-RG2X&j&xf=VsW3Q++nyi{#f9LFI6J8|QLKz~(#VcYZV z@nrYf*GYJ2AF9Z9?%v(mnKLtIX7}&E9;VYY)#rWcr3dLq{~f1!8mGIdNslx-*7GPG zHbIlv4+oc$vR3qX(Fjp$!DJv?R%PL`F&6Sum1}v8(R4^4fKsxd>^Ja zk~EU6aoSysG-;@DzJHhegS4l2$9kUWdz{{B1Y76Q<%34&ns<_I=hsrsH0LDk>+M;7 z>-A;S^6TA^$)3lH`Hi0U^xUK`QeU4hgkO`cr?=^K+7tpC+V{HNU>R1u)NW(_F6(SN z=UJcAg>38`q%X77CZoBdwG-`lrZ*sqB#?fW$BhT8u!(oOnmd&=EMUb!`Xi5fw>y$- zx$pIRYw=WceJnYRFvntRhA(XIiF7#9(?rrgNG1_=Q_n+vrh2oR$3WWX&+_wB-@`?8 zAn8!gP5Mj-y-L5NXIeQHZphfu$n|t1OFYaTXVkWbm-)TA#KA(M?TbjeCrqZ=6LdzB zcRyVdb|?CqY2>baxT&{9NnhV*8tW^D4)uRe{}WHlMd#x@2fH_=Z^<}faVA@h;F0DX zXk^}+wW-meq!Tg2EEn507xKMkDC?1YBt17Jp`Eu|={Kz-*T}TKK8Mokn(QK)cQwAB zZ5!lhx+V!<=a>YCWe&L8nW=%8b90#U3%kiBB93S%ad#m7ov&z5{uNBR?J9^7aluiM zH_JK_A;=`2CbHaivOiilHsOK7MR>E({8iirLaXG?x)}qZ8u^PoJCg1FjC+%jFBrf# zM5iNbEPoIq@JCzM$W-{t49471UWt4VE>h8TpttBd*B_`6O_6zIHe7B7ZX|J{IYa=_ z8s6HI7BFS_D-f$^lb1Cs!i8`PKF4Bnt9iQ4(~xOYg9|2|8pBHD-&Eh1>s=ynL*B<5 z-%Ahj4}K$u_oN%LCi;MO7t%x*akHVnkobefM(5}dQRo|%>}82Y`9rqbay<(Ub2SN6 zyJFQjRabz*%OM~A+kP>I?Kr+Diu)8c_h|H_*w^{+wtSz^%SlwUQ``@sV z`2TM$Wyh;nJJ0zF^N}fYts&!xMdFDkc%F=fHL01!8~C*w=eC?8g<8~wd0Pu)&cp$* zNO-uRn{!@#Dll8_kR@H_<$;3VYq%la z+V~ALi8jus_336gW}fLikzUX*)^z(4>1~FQ;c%kv(Cz1Kz z<~5wV(2^>PK0L#S<{zJHAL@x)y#0&?Y}qx_nzm1VAm`f|vMp+N=|RXnVyc2jYvmK&G;j|X8H6;SM7b{stk%i5G|(WkxvlzB6^4`PAbq9&2l+RYS2bpj zv)_^J%;~~`{x^JA>v4Shdn|g7zi9xDSBGF7{O&`DR@3vp?~ybtay-|fmiF`Q~gIHfW=M%9{RDyA4A{Yr4!xA&uZXRD{WOpO&Y~g9OO0;b#{aBoI z>z*NQV%{k0U=-J2@8#NnCEP6qH`!9yh~0@;Jo8xpk7UEC5XGMGN4;0KwyPC$xkqjH mb&c?eZp( Date: Wed, 20 Sep 2017 18:48:22 +0200 Subject: [PATCH 08/42] Update README.md ex1 --- tutorial/ex1/README.md | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/tutorial/ex1/README.md b/tutorial/ex1/README.md index 35fac0962e..1419b3378d 100644 --- a/tutorial/ex1/README.md +++ b/tutorial/ex1/README.md @@ -5,7 +5,7 @@ N2 is injected in an aquifer previously saturated with water with an injection rate of $`0.001~kg/m*s`$. The aquifer is situated 2700 m below see level and the domain size is 60 m x 40 m. It consists of two layers, a moderately permeable one ($`\Omega 1`$) and a lower permeable one ($`\Omega 2`$). - + ## Preparing the exercise @@ -27,14 +27,19 @@ Locate all the files you will need for this exercise (_exercise 1_) ### 2. Compiling and running an executable * Change to the build-directory + ```bash cd build-cmake/tutorial/exercise1 ``` + * Compile both executables `exercise1_2p` and `exercise1_2p2c` + ```bash make exercise1_2p exercise1_2p2c ``` + * Execute the two problems and inspect the result + ```bash ./exercise1_2p exercise1.input ./exercise1_2p2c exercise1.input @@ -62,10 +67,12 @@ code snippet We want to be able to set it at runtime. To this end, * use the following DuMuX macro to read a runtime parameter from the input file + ```c++ // read the injection rate from the input file at run time const auto injectionRate = GET_RUNTIME_PARAM_FROM_GROUP(TypeTag, , , ); ``` + * Replace ``,``,`` by what is appropriate for your case: * `` is the type of the parameter to read @@ -81,16 +88,21 @@ Again, you don't need to recompile the program. ### 5. Setting up a new executable (for a non-isothermal simulation) * Set up a new cc file called `exercise1_2pni.cc` by copying and renaming `exercise1_2p.cc` + ```bash cp exercise1_2p.cc exercise1_2pni.cc ``` + * In `exercise1_2pni.cc`, include the header `injection2pniproblem.hh` instead of the isothermal problem file `injection2pproblem.hh`. * Add a new executable in `CMakeLists.txt` by adding the lines + ```cmake dune_add_test(NAME injection2pniproblem SOURCES injection2pniproblem.cc) ``` + * Test that everything compiles without error + ```bash make # should rerun cmake make injection2pniproblem # builds new executable @@ -99,15 +111,17 @@ make injection2pniproblem # builds new executable ### 6. Setting up a non-isothermal __2pni__ test problem * Open the file `injection2pniproblem.hh`. It is a copy of the `injection2pproblem.hh` with some useful comments on how to implement a non-isothermal model. Look for comments containing + ```c++ // TODO: dumux-course-task ``` + * The following set-up should be realized: __Boundary conditions:__ Dirichlet conditions for the temperature with a temperature gradient of 0.03 K/m and a starting temperature of 283 K. __Initial conditions:__ The same temperature gradient as in the boundary conditions with an additional lens (with position: 20 < x < 30, 5 < y < 35), which has an initial temperature of 380 K. - + The non-isothermal model requires additional spatial parameters like the thermal conductivity. They are already implemented in `injection2pspatialparams.hh`, you just need to _uncomment_ them. -- GitLab From 11c7104df0b105ae654c8a71d4911973cf55bfbd Mon Sep 17 00:00:00 2001 From: Timo Koch Date: Wed, 20 Sep 2017 18:53:19 +0200 Subject: [PATCH 09/42] Move old tutorials to their own folders --- tutorial/CMakeLists.txt | 19 ++----------------- tutorial/ex1/CMakeLists.txt | 9 +++++++-- tutorial/ex1/README.md | 2 +- tutorial/tutorial_implicit/CMakeLists.txt | 11 +++++++++++ .../ex1b_tutorial_implicit.input.diff | 0 .../ex1b_tutorialproblem_implicit.diff | 0 .../ex1c_tutorialproblem_implicit.diff | 0 .../ex1d_tutorialproblem_implicit.diff | 0 .../ex1e_tutorialproblem_implicit.diff | 0 .../ex1f_tutorialspatialparams_implicit.diff | 0 .../ex1g_tutorialspatialparams_implicit.diff | 0 .../ex2_tutorial_implicit_input.diff | 0 .../ex2_tutorialproblem_implicit.hh | 0 .../ex2_tutorialspatialparams_implicit.hh | 0 .../ex3_tutorial_implicit.input | 0 .../ex3_tutorialproblem_implicit.diff | 0 .../ex3_tutorialspatialparams_implicit.diff | 0 .../solutions_implicit/ex4_benzene.hh | 0 .../ex4_tutorialproblem_implicit.diff | 0 .../ex5_tutorial_implicit.input | 0 .../ex5_tutorialproblem_implicit.hh | 0 .../ex5_tutorialspatialparams_implicit.hh | 0 .../tutorial_implicit.cc | 0 .../tutorial_implicit.input | 0 .../tutorialproblem_implicit.hh | 0 .../tutorialspatialparams_implicit.hh | 0 tutorial/tutorial_sequential/CMakeLists.txt | 11 +++++++++++ .../solutions_sequential/Ex1_a_input.diff | 0 .../solutions_sequential/Ex1_a_problem.diff | 0 .../solutions_sequential/Ex1_b_input.diff | 0 .../solutions_sequential/Ex1_b_problem.diff | 0 .../solutions_sequential/Ex1_c_problem.diff | 0 .../solutions_sequential/Ex1_d_input.diff | 0 .../solutions_sequential/Ex1_d_problem.diff | 0 .../solutions_sequential/Ex1_e_input.diff | 0 .../Ex1_e_spatialparams.diff | 0 .../Ex2_tutorial_sequential.input.diff | 0 .../Ex3tutorial_sequential.input.diff | 0 .../Ex3tutorialproblem_sequential.diff | 0 .../Ex3tutorialspatialparams_sequential.diff | 0 .../ex2tutorialproblem_sequential.hh | 0 .../ex2tutorialspatialparams_sequential.hh | 0 .../solutions_sequential/ex4_benzene.hh | 0 .../ex5_tutorial_sequential.input | 0 .../ex5_tutorialproblem_sequential.hh | 0 .../ex5_tutorialspatialparams_sequential.hh | 0 .../tutorial_sequential.cc | 0 .../tutorial_sequential.input | 0 .../tutorialproblem_sequential.hh | 0 .../tutorialspatialparams_sequential.hh | 0 50 files changed, 32 insertions(+), 20 deletions(-) create mode 100644 tutorial/tutorial_implicit/CMakeLists.txt rename tutorial/{ => tutorial_implicit}/solutions_implicit/ex1b_tutorial_implicit.input.diff (100%) rename tutorial/{ => tutorial_implicit}/solutions_implicit/ex1b_tutorialproblem_implicit.diff (100%) rename tutorial/{ => tutorial_implicit}/solutions_implicit/ex1c_tutorialproblem_implicit.diff (100%) rename tutorial/{ => tutorial_implicit}/solutions_implicit/ex1d_tutorialproblem_implicit.diff (100%) rename tutorial/{ => tutorial_implicit}/solutions_implicit/ex1e_tutorialproblem_implicit.diff (100%) rename tutorial/{ => tutorial_implicit}/solutions_implicit/ex1f_tutorialspatialparams_implicit.diff (100%) rename tutorial/{ => tutorial_implicit}/solutions_implicit/ex1g_tutorialspatialparams_implicit.diff (100%) rename tutorial/{ => tutorial_implicit}/solutions_implicit/ex2_tutorial_implicit_input.diff (100%) rename tutorial/{ => tutorial_implicit}/solutions_implicit/ex2_tutorialproblem_implicit.hh (100%) rename tutorial/{ => tutorial_implicit}/solutions_implicit/ex2_tutorialspatialparams_implicit.hh (100%) rename tutorial/{ => tutorial_implicit}/solutions_implicit/ex3_tutorial_implicit.input (100%) rename tutorial/{ => tutorial_implicit}/solutions_implicit/ex3_tutorialproblem_implicit.diff (100%) rename tutorial/{ => tutorial_implicit}/solutions_implicit/ex3_tutorialspatialparams_implicit.diff (100%) rename tutorial/{ => tutorial_implicit}/solutions_implicit/ex4_benzene.hh (100%) rename tutorial/{ => tutorial_implicit}/solutions_implicit/ex4_tutorialproblem_implicit.diff (100%) rename tutorial/{ => tutorial_implicit}/solutions_implicit/ex5_tutorial_implicit.input (100%) rename tutorial/{ => tutorial_implicit}/solutions_implicit/ex5_tutorialproblem_implicit.hh (100%) rename tutorial/{ => tutorial_implicit}/solutions_implicit/ex5_tutorialspatialparams_implicit.hh (100%) rename tutorial/{ => tutorial_implicit}/tutorial_implicit.cc (100%) rename tutorial/{ => tutorial_implicit}/tutorial_implicit.input (100%) rename tutorial/{ => tutorial_implicit}/tutorialproblem_implicit.hh (100%) rename tutorial/{ => tutorial_implicit}/tutorialspatialparams_implicit.hh (100%) create mode 100644 tutorial/tutorial_sequential/CMakeLists.txt rename tutorial/{ => tutorial_sequential}/solutions_sequential/Ex1_a_input.diff (100%) rename tutorial/{ => tutorial_sequential}/solutions_sequential/Ex1_a_problem.diff (100%) rename tutorial/{ => tutorial_sequential}/solutions_sequential/Ex1_b_input.diff (100%) rename tutorial/{ => tutorial_sequential}/solutions_sequential/Ex1_b_problem.diff (100%) rename tutorial/{ => tutorial_sequential}/solutions_sequential/Ex1_c_problem.diff (100%) rename tutorial/{ => tutorial_sequential}/solutions_sequential/Ex1_d_input.diff (100%) rename tutorial/{ => tutorial_sequential}/solutions_sequential/Ex1_d_problem.diff (100%) rename tutorial/{ => tutorial_sequential}/solutions_sequential/Ex1_e_input.diff (100%) rename tutorial/{ => tutorial_sequential}/solutions_sequential/Ex1_e_spatialparams.diff (100%) rename tutorial/{ => tutorial_sequential}/solutions_sequential/Ex2_tutorial_sequential.input.diff (100%) rename tutorial/{ => tutorial_sequential}/solutions_sequential/Ex3tutorial_sequential.input.diff (100%) rename tutorial/{ => tutorial_sequential}/solutions_sequential/Ex3tutorialproblem_sequential.diff (100%) rename tutorial/{ => tutorial_sequential}/solutions_sequential/Ex3tutorialspatialparams_sequential.diff (100%) rename tutorial/{ => tutorial_sequential}/solutions_sequential/ex2tutorialproblem_sequential.hh (100%) rename tutorial/{ => tutorial_sequential}/solutions_sequential/ex2tutorialspatialparams_sequential.hh (100%) rename tutorial/{ => tutorial_sequential}/solutions_sequential/ex4_benzene.hh (100%) rename tutorial/{ => tutorial_sequential}/solutions_sequential/ex5_tutorial_sequential.input (100%) rename tutorial/{ => tutorial_sequential}/solutions_sequential/ex5_tutorialproblem_sequential.hh (100%) rename tutorial/{ => tutorial_sequential}/solutions_sequential/ex5_tutorialspatialparams_sequential.hh (100%) rename tutorial/{ => tutorial_sequential}/tutorial_sequential.cc (100%) rename tutorial/{ => tutorial_sequential}/tutorial_sequential.input (100%) rename tutorial/{ => tutorial_sequential}/tutorialproblem_sequential.hh (100%) rename tutorial/{ => tutorial_sequential}/tutorialspatialparams_sequential.hh (100%) diff --git a/tutorial/CMakeLists.txt b/tutorial/CMakeLists.txt index f73220e201..7e89b59193 100644 --- a/tutorial/CMakeLists.txt +++ b/tutorial/CMakeLists.txt @@ -1,18 +1,3 @@ -add_input_file_links() - -add_dumux_test(tutorial_sequential tutorial_sequential tutorial_sequential.cc - ${CMAKE_CURRENT_BINARY_DIR}/tutorial_sequential) - -add_dumux_test(tutorial_implicit tutorial_implicit tutorial_implicit.cc - ${CMAKE_CURRENT_BINARY_DIR}/tutorial_implicit) - -#install sources -install(FILES -tutorial_implicit.cc -tutorial_sequential.cc -tutorialproblem_implicit.hh -tutorialproblem_sequential.hh -tutorialspatialparams_implicit.hh -tutorialspatialparams_sequential.hh -DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/dumux/tutorial) add_subdirectory(ex1) +add_subdirectory(tutorial_implicit) +add_subdirectory(tutorial_sequential) diff --git a/tutorial/ex1/CMakeLists.txt b/tutorial/ex1/CMakeLists.txt index 4b342a63b9..8f7d6e6d61 100644 --- a/tutorial/ex1/CMakeLists.txt +++ b/tutorial/ex1/CMakeLists.txt @@ -1,5 +1,10 @@ -add_executable(exercise1_2p exercise1_2p.cc exercise1_2p.cc) +# the immiscible two-phase simulation program +dune_add_test(NAME exercise1_2p + SOURCES exercise1_2p.cc) -add_executable(exercise1_2p2c exercise1_2p2c.cc exercise1_2p2c.cc) +# the compositional two-phase simulation program +dune_add_test(NAME exercise1_2p2c + SOURCES exercise1_2p2c.cc) +# add a symlink for the input file dune_symlink_to_source_files(FILES "exercise1.input") diff --git a/tutorial/ex1/README.md b/tutorial/ex1/README.md index 1419b3378d..dbd4c495a3 100644 --- a/tutorial/ex1/README.md +++ b/tutorial/ex1/README.md @@ -15,7 +15,7 @@ _Exercise 1_ deals with two problems: a two-phase immiscible problem (__2p__) an ### 1. Getting familiar with the code -Locate all the files you will need for this exercise (_exercise 1_) +Locate all the files you will need for this exercise * The __main file__ for the __2p__ problem: `exercise1_2p.cc` * The __problem file__ for the __2p__ problem: `injection2pproblem.hh` * The __main file__ for the __2p2c__ problem: `exercise1_2p2c.cc` diff --git a/tutorial/tutorial_implicit/CMakeLists.txt b/tutorial/tutorial_implicit/CMakeLists.txt new file mode 100644 index 0000000000..e73f579367 --- /dev/null +++ b/tutorial/tutorial_implicit/CMakeLists.txt @@ -0,0 +1,11 @@ +add_input_file_links() + +add_dumux_test(tutorial_implicit tutorial_implicit tutorial_implicit.cc + ${CMAKE_CURRENT_BINARY_DIR}/tutorial_implicit) + +#install sources +install(FILES +tutorial_implicit.cc +tutorialproblem_implicit.hh +tutorialspatialparams_implicit.hh +DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/dumux/tutorial/tutorial_implicit) diff --git a/tutorial/solutions_implicit/ex1b_tutorial_implicit.input.diff b/tutorial/tutorial_implicit/solutions_implicit/ex1b_tutorial_implicit.input.diff similarity index 100% rename from tutorial/solutions_implicit/ex1b_tutorial_implicit.input.diff rename to tutorial/tutorial_implicit/solutions_implicit/ex1b_tutorial_implicit.input.diff diff --git a/tutorial/solutions_implicit/ex1b_tutorialproblem_implicit.diff b/tutorial/tutorial_implicit/solutions_implicit/ex1b_tutorialproblem_implicit.diff similarity index 100% rename from tutorial/solutions_implicit/ex1b_tutorialproblem_implicit.diff rename to tutorial/tutorial_implicit/solutions_implicit/ex1b_tutorialproblem_implicit.diff diff --git a/tutorial/solutions_implicit/ex1c_tutorialproblem_implicit.diff b/tutorial/tutorial_implicit/solutions_implicit/ex1c_tutorialproblem_implicit.diff similarity index 100% rename from tutorial/solutions_implicit/ex1c_tutorialproblem_implicit.diff rename to tutorial/tutorial_implicit/solutions_implicit/ex1c_tutorialproblem_implicit.diff diff --git a/tutorial/solutions_implicit/ex1d_tutorialproblem_implicit.diff b/tutorial/tutorial_implicit/solutions_implicit/ex1d_tutorialproblem_implicit.diff similarity index 100% rename from tutorial/solutions_implicit/ex1d_tutorialproblem_implicit.diff rename to tutorial/tutorial_implicit/solutions_implicit/ex1d_tutorialproblem_implicit.diff diff --git a/tutorial/solutions_implicit/ex1e_tutorialproblem_implicit.diff b/tutorial/tutorial_implicit/solutions_implicit/ex1e_tutorialproblem_implicit.diff similarity index 100% rename from tutorial/solutions_implicit/ex1e_tutorialproblem_implicit.diff rename to tutorial/tutorial_implicit/solutions_implicit/ex1e_tutorialproblem_implicit.diff diff --git a/tutorial/solutions_implicit/ex1f_tutorialspatialparams_implicit.diff b/tutorial/tutorial_implicit/solutions_implicit/ex1f_tutorialspatialparams_implicit.diff similarity index 100% rename from tutorial/solutions_implicit/ex1f_tutorialspatialparams_implicit.diff rename to tutorial/tutorial_implicit/solutions_implicit/ex1f_tutorialspatialparams_implicit.diff diff --git a/tutorial/solutions_implicit/ex1g_tutorialspatialparams_implicit.diff b/tutorial/tutorial_implicit/solutions_implicit/ex1g_tutorialspatialparams_implicit.diff similarity index 100% rename from tutorial/solutions_implicit/ex1g_tutorialspatialparams_implicit.diff rename to tutorial/tutorial_implicit/solutions_implicit/ex1g_tutorialspatialparams_implicit.diff diff --git a/tutorial/solutions_implicit/ex2_tutorial_implicit_input.diff b/tutorial/tutorial_implicit/solutions_implicit/ex2_tutorial_implicit_input.diff similarity index 100% rename from tutorial/solutions_implicit/ex2_tutorial_implicit_input.diff rename to tutorial/tutorial_implicit/solutions_implicit/ex2_tutorial_implicit_input.diff diff --git a/tutorial/solutions_implicit/ex2_tutorialproblem_implicit.hh b/tutorial/tutorial_implicit/solutions_implicit/ex2_tutorialproblem_implicit.hh similarity index 100% rename from tutorial/solutions_implicit/ex2_tutorialproblem_implicit.hh rename to tutorial/tutorial_implicit/solutions_implicit/ex2_tutorialproblem_implicit.hh diff --git a/tutorial/solutions_implicit/ex2_tutorialspatialparams_implicit.hh b/tutorial/tutorial_implicit/solutions_implicit/ex2_tutorialspatialparams_implicit.hh similarity index 100% rename from tutorial/solutions_implicit/ex2_tutorialspatialparams_implicit.hh rename to tutorial/tutorial_implicit/solutions_implicit/ex2_tutorialspatialparams_implicit.hh diff --git a/tutorial/solutions_implicit/ex3_tutorial_implicit.input b/tutorial/tutorial_implicit/solutions_implicit/ex3_tutorial_implicit.input similarity index 100% rename from tutorial/solutions_implicit/ex3_tutorial_implicit.input rename to tutorial/tutorial_implicit/solutions_implicit/ex3_tutorial_implicit.input diff --git a/tutorial/solutions_implicit/ex3_tutorialproblem_implicit.diff b/tutorial/tutorial_implicit/solutions_implicit/ex3_tutorialproblem_implicit.diff similarity index 100% rename from tutorial/solutions_implicit/ex3_tutorialproblem_implicit.diff rename to tutorial/tutorial_implicit/solutions_implicit/ex3_tutorialproblem_implicit.diff diff --git a/tutorial/solutions_implicit/ex3_tutorialspatialparams_implicit.diff b/tutorial/tutorial_implicit/solutions_implicit/ex3_tutorialspatialparams_implicit.diff similarity index 100% rename from tutorial/solutions_implicit/ex3_tutorialspatialparams_implicit.diff rename to tutorial/tutorial_implicit/solutions_implicit/ex3_tutorialspatialparams_implicit.diff diff --git a/tutorial/solutions_implicit/ex4_benzene.hh b/tutorial/tutorial_implicit/solutions_implicit/ex4_benzene.hh similarity index 100% rename from tutorial/solutions_implicit/ex4_benzene.hh rename to tutorial/tutorial_implicit/solutions_implicit/ex4_benzene.hh diff --git a/tutorial/solutions_implicit/ex4_tutorialproblem_implicit.diff b/tutorial/tutorial_implicit/solutions_implicit/ex4_tutorialproblem_implicit.diff similarity index 100% rename from tutorial/solutions_implicit/ex4_tutorialproblem_implicit.diff rename to tutorial/tutorial_implicit/solutions_implicit/ex4_tutorialproblem_implicit.diff diff --git a/tutorial/solutions_implicit/ex5_tutorial_implicit.input b/tutorial/tutorial_implicit/solutions_implicit/ex5_tutorial_implicit.input similarity index 100% rename from tutorial/solutions_implicit/ex5_tutorial_implicit.input rename to tutorial/tutorial_implicit/solutions_implicit/ex5_tutorial_implicit.input diff --git a/tutorial/solutions_implicit/ex5_tutorialproblem_implicit.hh b/tutorial/tutorial_implicit/solutions_implicit/ex5_tutorialproblem_implicit.hh similarity index 100% rename from tutorial/solutions_implicit/ex5_tutorialproblem_implicit.hh rename to tutorial/tutorial_implicit/solutions_implicit/ex5_tutorialproblem_implicit.hh diff --git a/tutorial/solutions_implicit/ex5_tutorialspatialparams_implicit.hh b/tutorial/tutorial_implicit/solutions_implicit/ex5_tutorialspatialparams_implicit.hh similarity index 100% rename from tutorial/solutions_implicit/ex5_tutorialspatialparams_implicit.hh rename to tutorial/tutorial_implicit/solutions_implicit/ex5_tutorialspatialparams_implicit.hh diff --git a/tutorial/tutorial_implicit.cc b/tutorial/tutorial_implicit/tutorial_implicit.cc similarity index 100% rename from tutorial/tutorial_implicit.cc rename to tutorial/tutorial_implicit/tutorial_implicit.cc diff --git a/tutorial/tutorial_implicit.input b/tutorial/tutorial_implicit/tutorial_implicit.input similarity index 100% rename from tutorial/tutorial_implicit.input rename to tutorial/tutorial_implicit/tutorial_implicit.input diff --git a/tutorial/tutorialproblem_implicit.hh b/tutorial/tutorial_implicit/tutorialproblem_implicit.hh similarity index 100% rename from tutorial/tutorialproblem_implicit.hh rename to tutorial/tutorial_implicit/tutorialproblem_implicit.hh diff --git a/tutorial/tutorialspatialparams_implicit.hh b/tutorial/tutorial_implicit/tutorialspatialparams_implicit.hh similarity index 100% rename from tutorial/tutorialspatialparams_implicit.hh rename to tutorial/tutorial_implicit/tutorialspatialparams_implicit.hh diff --git a/tutorial/tutorial_sequential/CMakeLists.txt b/tutorial/tutorial_sequential/CMakeLists.txt new file mode 100644 index 0000000000..d4ddb99d63 --- /dev/null +++ b/tutorial/tutorial_sequential/CMakeLists.txt @@ -0,0 +1,11 @@ +add_input_file_links() + +add_dumux_test(tutorial_sequential tutorial_sequential tutorial_sequential.cc + ${CMAKE_CURRENT_BINARY_DIR}/tutorial_sequential) + +#install sources +install(FILES +tutorial_sequential.cc +tutorialproblem_sequential.hh +tutorialspatialparams_sequential.hh +DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/dumux/tutorial/tutorial_sequential) diff --git a/tutorial/solutions_sequential/Ex1_a_input.diff b/tutorial/tutorial_sequential/solutions_sequential/Ex1_a_input.diff similarity index 100% rename from tutorial/solutions_sequential/Ex1_a_input.diff rename to tutorial/tutorial_sequential/solutions_sequential/Ex1_a_input.diff diff --git a/tutorial/solutions_sequential/Ex1_a_problem.diff b/tutorial/tutorial_sequential/solutions_sequential/Ex1_a_problem.diff similarity index 100% rename from tutorial/solutions_sequential/Ex1_a_problem.diff rename to tutorial/tutorial_sequential/solutions_sequential/Ex1_a_problem.diff diff --git a/tutorial/solutions_sequential/Ex1_b_input.diff b/tutorial/tutorial_sequential/solutions_sequential/Ex1_b_input.diff similarity index 100% rename from tutorial/solutions_sequential/Ex1_b_input.diff rename to tutorial/tutorial_sequential/solutions_sequential/Ex1_b_input.diff diff --git a/tutorial/solutions_sequential/Ex1_b_problem.diff b/tutorial/tutorial_sequential/solutions_sequential/Ex1_b_problem.diff similarity index 100% rename from tutorial/solutions_sequential/Ex1_b_problem.diff rename to tutorial/tutorial_sequential/solutions_sequential/Ex1_b_problem.diff diff --git a/tutorial/solutions_sequential/Ex1_c_problem.diff b/tutorial/tutorial_sequential/solutions_sequential/Ex1_c_problem.diff similarity index 100% rename from tutorial/solutions_sequential/Ex1_c_problem.diff rename to tutorial/tutorial_sequential/solutions_sequential/Ex1_c_problem.diff diff --git a/tutorial/solutions_sequential/Ex1_d_input.diff b/tutorial/tutorial_sequential/solutions_sequential/Ex1_d_input.diff similarity index 100% rename from tutorial/solutions_sequential/Ex1_d_input.diff rename to tutorial/tutorial_sequential/solutions_sequential/Ex1_d_input.diff diff --git a/tutorial/solutions_sequential/Ex1_d_problem.diff b/tutorial/tutorial_sequential/solutions_sequential/Ex1_d_problem.diff similarity index 100% rename from tutorial/solutions_sequential/Ex1_d_problem.diff rename to tutorial/tutorial_sequential/solutions_sequential/Ex1_d_problem.diff diff --git a/tutorial/solutions_sequential/Ex1_e_input.diff b/tutorial/tutorial_sequential/solutions_sequential/Ex1_e_input.diff similarity index 100% rename from tutorial/solutions_sequential/Ex1_e_input.diff rename to tutorial/tutorial_sequential/solutions_sequential/Ex1_e_input.diff diff --git a/tutorial/solutions_sequential/Ex1_e_spatialparams.diff b/tutorial/tutorial_sequential/solutions_sequential/Ex1_e_spatialparams.diff similarity index 100% rename from tutorial/solutions_sequential/Ex1_e_spatialparams.diff rename to tutorial/tutorial_sequential/solutions_sequential/Ex1_e_spatialparams.diff diff --git a/tutorial/solutions_sequential/Ex2_tutorial_sequential.input.diff b/tutorial/tutorial_sequential/solutions_sequential/Ex2_tutorial_sequential.input.diff similarity index 100% rename from tutorial/solutions_sequential/Ex2_tutorial_sequential.input.diff rename to tutorial/tutorial_sequential/solutions_sequential/Ex2_tutorial_sequential.input.diff diff --git a/tutorial/solutions_sequential/Ex3tutorial_sequential.input.diff b/tutorial/tutorial_sequential/solutions_sequential/Ex3tutorial_sequential.input.diff similarity index 100% rename from tutorial/solutions_sequential/Ex3tutorial_sequential.input.diff rename to tutorial/tutorial_sequential/solutions_sequential/Ex3tutorial_sequential.input.diff diff --git a/tutorial/solutions_sequential/Ex3tutorialproblem_sequential.diff b/tutorial/tutorial_sequential/solutions_sequential/Ex3tutorialproblem_sequential.diff similarity index 100% rename from tutorial/solutions_sequential/Ex3tutorialproblem_sequential.diff rename to tutorial/tutorial_sequential/solutions_sequential/Ex3tutorialproblem_sequential.diff diff --git a/tutorial/solutions_sequential/Ex3tutorialspatialparams_sequential.diff b/tutorial/tutorial_sequential/solutions_sequential/Ex3tutorialspatialparams_sequential.diff similarity index 100% rename from tutorial/solutions_sequential/Ex3tutorialspatialparams_sequential.diff rename to tutorial/tutorial_sequential/solutions_sequential/Ex3tutorialspatialparams_sequential.diff diff --git a/tutorial/solutions_sequential/ex2tutorialproblem_sequential.hh b/tutorial/tutorial_sequential/solutions_sequential/ex2tutorialproblem_sequential.hh similarity index 100% rename from tutorial/solutions_sequential/ex2tutorialproblem_sequential.hh rename to tutorial/tutorial_sequential/solutions_sequential/ex2tutorialproblem_sequential.hh diff --git a/tutorial/solutions_sequential/ex2tutorialspatialparams_sequential.hh b/tutorial/tutorial_sequential/solutions_sequential/ex2tutorialspatialparams_sequential.hh similarity index 100% rename from tutorial/solutions_sequential/ex2tutorialspatialparams_sequential.hh rename to tutorial/tutorial_sequential/solutions_sequential/ex2tutorialspatialparams_sequential.hh diff --git a/tutorial/solutions_sequential/ex4_benzene.hh b/tutorial/tutorial_sequential/solutions_sequential/ex4_benzene.hh similarity index 100% rename from tutorial/solutions_sequential/ex4_benzene.hh rename to tutorial/tutorial_sequential/solutions_sequential/ex4_benzene.hh diff --git a/tutorial/solutions_sequential/ex5_tutorial_sequential.input b/tutorial/tutorial_sequential/solutions_sequential/ex5_tutorial_sequential.input similarity index 100% rename from tutorial/solutions_sequential/ex5_tutorial_sequential.input rename to tutorial/tutorial_sequential/solutions_sequential/ex5_tutorial_sequential.input diff --git a/tutorial/solutions_sequential/ex5_tutorialproblem_sequential.hh b/tutorial/tutorial_sequential/solutions_sequential/ex5_tutorialproblem_sequential.hh similarity index 100% rename from tutorial/solutions_sequential/ex5_tutorialproblem_sequential.hh rename to tutorial/tutorial_sequential/solutions_sequential/ex5_tutorialproblem_sequential.hh diff --git a/tutorial/solutions_sequential/ex5_tutorialspatialparams_sequential.hh b/tutorial/tutorial_sequential/solutions_sequential/ex5_tutorialspatialparams_sequential.hh similarity index 100% rename from tutorial/solutions_sequential/ex5_tutorialspatialparams_sequential.hh rename to tutorial/tutorial_sequential/solutions_sequential/ex5_tutorialspatialparams_sequential.hh diff --git a/tutorial/tutorial_sequential.cc b/tutorial/tutorial_sequential/tutorial_sequential.cc similarity index 100% rename from tutorial/tutorial_sequential.cc rename to tutorial/tutorial_sequential/tutorial_sequential.cc diff --git a/tutorial/tutorial_sequential.input b/tutorial/tutorial_sequential/tutorial_sequential.input similarity index 100% rename from tutorial/tutorial_sequential.input rename to tutorial/tutorial_sequential/tutorial_sequential.input diff --git a/tutorial/tutorialproblem_sequential.hh b/tutorial/tutorial_sequential/tutorialproblem_sequential.hh similarity index 100% rename from tutorial/tutorialproblem_sequential.hh rename to tutorial/tutorial_sequential/tutorialproblem_sequential.hh diff --git a/tutorial/tutorialspatialparams_sequential.hh b/tutorial/tutorial_sequential/tutorialspatialparams_sequential.hh similarity index 100% rename from tutorial/tutorialspatialparams_sequential.hh rename to tutorial/tutorial_sequential/tutorialspatialparams_sequential.hh -- GitLab From dfac295498722a5c8b6379c69b7034ef76fec215 Mon Sep 17 00:00:00 2001 From: Timo Koch Date: Wed, 20 Sep 2017 19:52:18 +0200 Subject: [PATCH 10/42] Add some stuff for exercise 2 --- tutorial/ex2/CMakeLists.txt | 6 + tutorial/ex2/README.md | 128 ++++++++ tutorial/ex2/exercise2.cc | 67 +++++ tutorial/ex2/exercise2.input | 18 ++ tutorial/ex2/injection2p2cproblem.hh | 367 +++++++++++++++++++++++ tutorial/ex2/injection2pspatialparams.hh | 253 ++++++++++++++++ 6 files changed, 839 insertions(+) create mode 100644 tutorial/ex2/CMakeLists.txt create mode 100644 tutorial/ex2/README.md create mode 100644 tutorial/ex2/exercise2.cc create mode 100755 tutorial/ex2/exercise2.input create mode 100644 tutorial/ex2/injection2p2cproblem.hh create mode 100644 tutorial/ex2/injection2pspatialparams.hh diff --git a/tutorial/ex2/CMakeLists.txt b/tutorial/ex2/CMakeLists.txt new file mode 100644 index 0000000000..d53f775c2a --- /dev/null +++ b/tutorial/ex2/CMakeLists.txt @@ -0,0 +1,6 @@ +# a compositional two-phase simulation program +dune_add_test(NAME exercise2 + SOURCES exercise2.cc) + +# add a symlink for the input file +dune_symlink_to_source_files(FILES "exercise2.input") diff --git a/tutorial/ex2/README.md b/tutorial/ex2/README.md new file mode 100644 index 0000000000..49de2542c7 --- /dev/null +++ b/tutorial/ex2/README.md @@ -0,0 +1,128 @@ +# Exercise #2 (DuMuX course) + +## Problem set-up + +The problem setup is identical to the previous [_exercise 1_](https://git.iws.uni-stuttgart.de/dumux-repositories/dumux/blob/6c2ca5dd000599f793f89fe5e3fc69ef9c9d8b73/tutorial/ex1/README.md) with a lower injection rate of 1e-6 kg/(m*s) so that diffusion plays a more dominant role in the transport process. + +## Preparing the exercise + +* Navigate to the directory `dumux/tutorial/dumux-course` + +_Exercise 2_ deals with a two-phase compositional problem (__2p2c__). Goal is to learn how to use compile and runtime parameters and the _DuMuX property system_. + +### 1. Getting familiar with the code + +Locate all the files you will need for this exercise +* The __main file__: `exercise2.cc` +* The __problem file__: `injection2p2cproblem.hh` +* The __spatial parameters file__: `injection2pspatialparams.hh` +* The __input file__: `exercise2.input` +* Two header files containing: + * a custom __local residual__ in: `mylocalresidual.hh` + * a custom __material law__ in:: `mymateriallaw.hh` + +### 2. Compiling and running the program + +* Change to the build-directory + +```bash +cd build-cmake/tutorial/exercise2 +``` + +* Compile the executable `exercise2` + +```bash +make exercise2 +``` + +* Execute the two problems and inspect the result + +```bash +./exercise2 +``` +Note: Because the input file has the same name as the +executable, DuMuX will find it automatically. + +If gnuplot is installed on your system, you should see a plot of the capillary pressure - saturation relationship. + +### 3. Implement and use a different material law + +DuMuX uses the term _material law_ to describe the law used to compute +* pc-Sw relations +* kr-Sw relations +* their inverse relations + +The file `mymateriallaw.hh` contains a custom implementation of such a material law. + +* Implement the method `Scalar pc(Scalar sw)` by implementing your own capillary pressure relationship, e.g. pc(Sw) = 1e5*(1-Sw). + +The type (i.e. C++ type) of the material law is set in the file `injection2pspatialparams.hh` by using the DuMuX property system + +```c++ +SET_PROP(InjectionSpatialParams, MaterialLaw) +{ + using Scalar = typename GET_PROP_TYPE(TypeTag, Scalar); + using type = EffToAbsLaw>; +}; +``` + +* Make DuMuX use your own material law by including the header `mymateriallaw.hh` and changing the alias `type`. This will make sure that your material law is used everywhere else in the code. + +Verify your changes by recompiling and running the program. You should see a plot of your new function. + +### 4. Implement your own local residual + +Most types in DuMuX are properties that can be changed just like the material law. In the following task we implement our own 2p2c local residual, i.e. the class that computes the element residual in every Newton step. The file `mylocalresidual.hh` contains a copy of the original local residual class used for the 2p2c model renamed to `template class MyTwoPTwoCLocalResidual`. + +* Make DuMuX use this new local residual by setting the corresponding property in the `Property` namespace in the file `injection2p2cproblem.hh` + +```c++ +// note that every property struct knows about TypeTag +SET_PROP(Injection2p2cProblem, LocalResidual) +{ + using type = MyTwoPTwoCLocalResidualocal; +}; + +// or using the convenience macro +SET_TYPE_PROP(Injection2p2cProblem, LocalResidual, + MyTwoPTwoCLocalResidualocal); +``` + +* Implement an output to the terminal in the constructor of `MyTwoPTwoCLocalResidual` e.g. + +```c++ +MyTwoPTwoCLocalResidual() +{ + std::cout << "Using MyTwoPTwoCLocalResidual." << std::endl; +} +``` + +* Verify you are using the new class by compiling and running the new program and inspecting the terminal output. + +You want to make the new local residual special by adding a switch enabling / disabling diffusion. We will achieve this with a DuMuX parameter, a parameter read from the input file that defaults to a property value if the input file doesn't contain the parameter. + +* Create a new `TypeTag` node, a new `PropertyTag`, and set a default in the `mylocalresidual.hh` file by adding + +```c++ +namespace Dumux { + +namespace Properties +{ + NEW_TYPE_TAG(MyLocalResidualParams); // creates a new TypeTag node + NEW_PROP_TAG(ProblemEnableDiffusion); // creates a new property + SET_BOOL_PROP(MyLocalResidualParams, + ProblemEnableDiffusion, true); // set a default value +} +... +``` + +* Modify the `computeFlux` method to only call the `diffusiveFlux` method if diffusion is enabled. You can get the new parameter by adding the lines +```c++ +// ... in the constructor of MyTwoPTwoCLocalResidual + enableDiffusion_ = GET_PARAM_FROM_GROUP(TypeTag, bool, + Problem, EnableDiffusion); + +// ... in the private member section of MyTwoPTwoCLocalResidual +private: + bool enableDiffusion_; +``` diff --git a/tutorial/ex2/exercise2.cc b/tutorial/ex2/exercise2.cc new file mode 100644 index 0000000000..aba0b0e8c7 --- /dev/null +++ b/tutorial/ex2/exercise2.cc @@ -0,0 +1,67 @@ +// -*- 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 Test for the two-phase two-component CC model. + */ +#include +#include "injection2p2cproblem.hh" +#include + +/*! + * \brief Provides an interface for customizing error messages associated with + * reading in parameters. + * + * \param progName The name of the program, that was tried to be started. + * \param errorMsg The error message that was issued by the start function. + * Comprises the thing that went wrong and a general help message. + */ +void usage(const char *progName, const std::string &errorMsg) +{ + if (errorMsg.size() > 0) { + std::string errorMessageOut = "\nUsage: "; + errorMessageOut += progName; + errorMessageOut += " [options]\n"; + errorMessageOut += errorMsg; + errorMessageOut += "\n\nThe list of mandatory options for this program is:\n" + "\t-TimeManager.TEnd End of the simulation [s] \n" + "\t-TimeManager.DtInitial Initial timestep size [s] \n" + "\t-Grid.File Name of the file containing the grid \n" + "\t definition in DGF format\n" + "\t-FluidSystem.NTemperature Number of tabularization entries [-] \n" + "\t-FluidSystem.NPressure Number of tabularization entries [-] \n" + "\t-FluidSystem.PressureLow Low end for tabularization of fluid properties [Pa] \n" + "\t-FluidSystem.PressureHigh High end for tabularization of fluid properties [Pa] \n" + "\t-FluidSystem.TemperatureLow Low end for tabularization of fluid properties [Pa] \n" + "\t-FluidSystem.TemperatureHigh High end for tabularization of fluid properties [Pa] \n" + "\t-SimulationControl.Name The name of the output files [-] \n" + "\t-InitialConditions.Temperature Initial temperature in the reservoir [K] \n" + "\t-InitialConditions.DepthBOR Depth below ground surface [m] \n"; + + std::cout << errorMessageOut + << "\n"; + } +} + +int main(int argc, char** argv) +{ + typedef TTAG(Injection2p2pcCCProblem) ProblemTypeTag; + return Dumux::start(argc, argv, usage); +} diff --git a/tutorial/ex2/exercise2.input b/tutorial/ex2/exercise2.input new file mode 100755 index 0000000000..a4e055be8c --- /dev/null +++ b/tutorial/ex2/exercise2.input @@ -0,0 +1,18 @@ +[TimeManager] +DtInitial = 250 # [s] +TEnd = 1e7 # [s] + +[Grid] +LowerLeft = 0 0 +UpperRight = 60 40 +Cells = 24 16 + +[Problem] +MaxDepth = 2700.0 + +[Newton] +WriteConvergence = 1 # write convergence behaviour to disk? + +[SpatialParams] +EntryPressureFine = 4.5e4 +EntryPressureCoarse = 1e4 diff --git a/tutorial/ex2/injection2p2cproblem.hh b/tutorial/ex2/injection2p2cproblem.hh new file mode 100644 index 0000000000..a63bc73d1c --- /dev/null +++ b/tutorial/ex2/injection2p2cproblem.hh @@ -0,0 +1,367 @@ +// -*- 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 Problem where air is injected under a low permeable layer in a depth of 2700m. + */ +#ifndef DUMUX_INJECTION_2P2C_PROBLEM_HH +#define DUMUX_INJECTION_2P2C_PROBLEM_HH + +#include +#include +#include + +#include "injection2pspatialparams.hh" + +namespace Dumux +{ + +template +class Injection2p2cProblem; + +namespace Properties +{ +NEW_TYPE_TAG(Injection2p2cProblem, INHERITS_FROM(TwoPTwoC, InjectionSpatialParams)); +NEW_TYPE_TAG(Injection2p2cBoxProblem, INHERITS_FROM(BoxModel, Injection2p2cProblem)); +NEW_TYPE_TAG(Injection2p2pcCCProblem, INHERITS_FROM(CCModel, Injection2p2cProblem)); + +// Set the grid type +SET_TYPE_PROP(Injection2p2cProblem, Grid, Dune::YaspGrid<2>); + +// Set the problem property +SET_TYPE_PROP(Injection2p2cProblem, Problem, Injection2p2cProblem); + +// Set fluid configuration +SET_TYPE_PROP(Injection2p2cProblem, + FluidSystem, + FluidSystems::H2ON2); + +// Define whether mole(true) or mass (false) fractions are used +SET_BOOL_PROP(Injection2p2cProblem, UseMoles, true); +} + + +/*! + * \ingroup TwoPTwoCModel + * \ingroup ImplicitTestProblems + * \brief Problem where air is injected under a low permeable layer in a depth of 2700m. + * + * The domain is sized 60m times 40m and consists of two layers, a moderately + * permeable one (\f$ K=10e-12\f$) for \f$ y<22m\f$ and one with a lower permeablility (\f$ K=10e-13\f$) + * in the rest of the domain. + * + * A mixture of Nitrogen and Water vapor, which is composed according to the prevailing conditions (temperature, pressure) + * enters a water-filled aquifer. This is realized with a solution-dependent Neumann boundary condition at the right boundary + * (\f$ 7m./exercise1_2p2c -parameterFile exercise1.input> + */ +template +class Injection2p2cProblem : public ImplicitPorousMediaProblem +{ + typedef ImplicitPorousMediaProblem ParentType; + + typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; + typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; + typedef typename GET_PROP_TYPE(TypeTag, FluidSystem) FluidSystem; + + enum { + // Grid and world dimension + dim = GridView::dimension, + dimWorld = GridView::dimensionworld + }; + + // copy some indices for convenience + typedef typename GET_PROP_TYPE(TypeTag, Indices) Indices; + enum { + wPhaseIdx = Indices::wPhaseIdx, + nPhaseIdx = Indices::nPhaseIdx, + + + wCompIdx = FluidSystem::wCompIdx, + nCompIdx = FluidSystem::nCompIdx, + + contiH2OEqIdx = Indices::contiWEqIdx, + contiN2EqIdx = Indices::contiNEqIdx + }; + + + typedef typename GET_PROP_TYPE(TypeTag, PrimaryVariables) PrimaryVariables; + typedef typename GET_PROP_TYPE(TypeTag, ElementVolumeVariables) ElementVolumeVariables; + typedef typename GET_PROP_TYPE(TypeTag, BoundaryTypes) BoundaryTypes; + typedef typename GET_PROP_TYPE(TypeTag, TimeManager) TimeManager; + + typedef typename GridView::template Codim<0>::Entity Element; + typedef typename GridView::template Codim::Entity Vertex; + typedef typename GridView::Intersection Intersection; + + typedef typename GET_PROP_TYPE(TypeTag, FVElementGeometry) FVElementGeometry; + + typedef Dune::FieldVector GlobalPosition; + + enum { isBox = GET_PROP_VALUE(TypeTag, ImplicitIsBox) }; + + //! property that defines whether mole or mass fractions are used + static const bool useMoles = GET_PROP_VALUE(TypeTag, UseMoles); + +public: + /*! + * \brief The constructor + * + * \param timeManager The time manager + * \param gridView The grid view + */ + Injection2p2cProblem(TimeManager &timeManager, + const GridView &gridView) + : ParentType(timeManager, gridView) + { + maxDepth_ = GET_RUNTIME_PARAM(TypeTag, Scalar, Problem.MaxDepth); + + // initialize the tables of the fluid system + FluidSystem::init(/*tempMin=*/273.15, + /*tempMax=*/423.15, + /*numTemp=*/50, + /*pMin=*/0.0, + /*pMax=*/30e6, + /*numP=*/300); + + //stateing in the console whether mole or mass fractions are used + if(useMoles) + { + std::cout<<"problem uses mole-fractions"<model().globalPhaseStorage(storageW, wPhaseIdx); + this->model().globalPhaseStorage(storageN, nPhaseIdx); + + // Write mass balance information for rank 0 + if (this->gridView().comm().rank() == 0) { + std::cout<<"Storage: wetting=[" << storageW << "]" + << " nonwetting=[" << storageN << "]\n"; + } + } + + + /*! + * \name Problem parameters + */ + // \{ + + /*! + * \brief Returns the problem name + * + * This is used as a prefix for files generated by the simulation. + */ + const std::string name() const + { return "injection-2p2c"; } + + /*! + * \brief Returns the temperature \f$ K \f$ + */ + Scalar temperature() const + { + return 273.15 + 30; // [K] + } + + /*! + * \brief Returns the source term + * + * \param values Stores the source values for the conservation equations in + * \f$ [ \textnormal{unit of primary variable} / (m^\textrm{dim} \cdot s )] \f$ + * \param globalPos The global position + */ + void sourceAtPos(PrimaryVariables &values, + const GlobalPosition &globalPos) const + { + values = 0; + } + + // \} + + /*! + * \name Boundary conditions + */ + // \{ + + /*! + * \brief Specifies which kind of boundary condition should be + * used for which equation on a given boundary segment + * + * \param values Stores the value of the boundary type + * \param globalPos The global position + */ + void boundaryTypesAtPos(BoundaryTypes &values, + const GlobalPosition &globalPos) const + { + if (globalPos[0] < eps_) + values.setAllDirichlet(); + else + values.setAllNeumann(); + } + + /*! + * \brief Evaluates the boundary conditions for a Dirichlet + * boundary segment + * + * \param values Stores the Dirichlet values for the conservation equations in + * \f$ [ \textnormal{unit of primary variable} ] \f$ + * \param globalPos The global position + */ + void dirichletAtPos(PrimaryVariables &values, const GlobalPosition &globalPos) const + { + initial_(values, globalPos); + } + + /*! + * \brief Evaluates the boundary conditions for a Neumann + * boundary segment in dependency on the current solution. + * + * \param values Stores the Neumann values for the conservation equations in + * \f$ [ \textnormal{unit of conserved quantity} / (m^(dim-1) \cdot s )] \f$ + * \param element The finite element + * \param fvGeometry The finite volume geometry of the element + * \param intersection The intersection between element and boundary + * \param scvIdx The local index of the sub-control volume + * \param boundaryFaceIdx The index of the boundary face + * \param elemVolVars All volume variables for the element + * + * This method is used for cases, when the Neumann condition depends on the + * solution and requires some quantities that are specific to the fully-implicit method. + * The \a values store the mass flux of each phase normal to the boundary. + * Negative values indicate an inflow. + */ + void solDependentNeumann(PrimaryVariables &values, + const Element &element, + const FVElementGeometry &fvGeometry, + const Intersection &intersection, + const int scvIdx, + const int boundaryFaceIdx, + const ElementVolumeVariables &elemVolVars) const + { + values = 0; + + GlobalPosition globalPos; + if (isBox) + globalPos = element.geometry().corner(scvIdx); + else + globalPos = intersection.geometry().center(); + + Scalar injectedPhaseMass = 1e-3; + Scalar moleFracW = elemVolVars[scvIdx].moleFraction(nPhaseIdx, wCompIdx); + if (globalPos[1] < 15 + eps_ && globalPos[1] > 7 -eps_) { + values[contiN2EqIdx] = -(1-moleFracW)*injectedPhaseMass/FluidSystem::molarMass(nCompIdx); //mole/(m^2*s) -> kg/(s*m^2) + values[contiH2OEqIdx] = -moleFracW*injectedPhaseMass/FluidSystem::molarMass(wCompIdx); //mole/(m^2*s) -> kg/(s*m^2) + } + } + + // \} + + /*! + * \name Volume terms + */ + // \{ + + /*! + * \brief Evaluates the initial values for a control volume + * + * \param values Stores the initial values for the conservation equations in + * \f$ [ \textnormal{unit of primary variables} ] \f$ + * \param globalPos The global position + */ + void initialAtPos(PrimaryVariables &values, const GlobalPosition &globalPos) const + { + initial_(values, globalPos); + } + + /*! + * \brief Return the initial phase state inside a control volume. + * + * \param globalPos The global position + */ + int initialPhasePresenceAtPos(const GlobalPosition &globalPos) const + { return Indices::wPhaseOnly; } + + // \} + +private: + /*! + * \brief Evaluates the initial values for a control volume + * + * The internal method for the initial condition + * + * \param values Stores the initial values for the conservation equations in + * \f$ [ \textnormal{unit of primary variables} ] \f$ + * \param globalPos The global position + */ + void initial_(PrimaryVariables &values, + const GlobalPosition &globalPos) const + { + Scalar densityW = FluidSystem::H2O::liquidDensity(temperature(), 1e5); + + Scalar pl = 1e5 - densityW*this->gravity()[1]*(maxDepth_ - globalPos[1]); + Scalar moleFracLiquidN2 = pl*0.95/BinaryCoeff::H2O_N2::henry(temperature()); + Scalar moleFracLiquidH2O = 1.0 - moleFracLiquidN2; + + Scalar meanM = + FluidSystem::molarMass(wCompIdx)*moleFracLiquidH2O + + FluidSystem::molarMass(nCompIdx)*moleFracLiquidN2; + if(useMoles) + { + //mole-fraction formulation + values[Indices::switchIdx] = moleFracLiquidN2; + } + else + { + //mass fraction formulation + Scalar massFracLiquidN2 = moleFracLiquidN2*FluidSystem::molarMass(nCompIdx)/meanM; + values[Indices::switchIdx] = massFracLiquidN2; + } + values[Indices::pressureIdx] = pl; + } + + + static constexpr Scalar eps_ = 1e-6; + Scalar maxDepth_; + +}; +} //end namespace + +#endif diff --git a/tutorial/ex2/injection2pspatialparams.hh b/tutorial/ex2/injection2pspatialparams.hh new file mode 100644 index 0000000000..fc85aa4c21 --- /dev/null +++ b/tutorial/ex2/injection2pspatialparams.hh @@ -0,0 +1,253 @@ +// -*- 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 Definition of the spatial parameters for the injection problem + * which uses the isothermal two-phase two-component + * fully implicit model. + */ + +#ifndef DUMUX_INJECTION_SPATIAL_PARAMS_HH +#define DUMUX_INJECTION_SPATIAL_PARAMS_HH + +#include +#include +#include + +#include + +namespace Dumux +{ + +//forward declaration +template +class InjectionSpatialParams; + +namespace Properties +{ +// The spatial parameters TypeTag +NEW_TYPE_TAG(InjectionSpatialParams); + +// Set the spatial parameters +SET_TYPE_PROP(InjectionSpatialParams, SpatialParams, InjectionSpatialParams); + +// Set the material law parameterized by absolute saturations +SET_TYPE_PROP(InjectionSpatialParams, + MaterialLaw, + EffToAbsLaw >); +} + +/*! + * \ingroup TwoPTwoCModel + * \ingroup ImplicitTestProblems + * \brief Definition of the spatial parameters for the injection problem + * which uses the isothermal two-phase two-component + * fully implicit model. + */ +template +class InjectionSpatialParams : public ImplicitSpatialParams +{ + typedef ImplicitSpatialParams ParentType; + typedef typename GET_PROP_TYPE(TypeTag, Grid) Grid; + typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; + typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; + typedef typename Grid::ctype CoordScalar; + typedef typename GET_PROP_TYPE(TypeTag, FluidSystem) FluidSystem; + + enum { + dim=GridView::dimension, + dimWorld=GridView::dimensionworld + }; + + typedef Dune::FieldVector GlobalPosition; + + typedef typename GET_PROP_TYPE(TypeTag, FVElementGeometry) FVElementGeometry; + typedef typename GridView::template Codim<0>::Entity Element; + +public: + typedef typename GET_PROP_TYPE(TypeTag, MaterialLaw) MaterialLaw; + typedef typename MaterialLaw::Params MaterialLawParams; + + /*! + * \brief The constructor + * + * \param gridView The grid view + */ + InjectionSpatialParams(const GridView &gridView) + : ParentType(gridView) + { + layerBottom_ = 25.0; + + // intrinsic permeabilities + fineK_ = 1e-13; + coarseK_ = 1e-12; + + // porosities + finePorosity_ = 0.2; + coarsePorosity_ = 0.4; + + //materialLawParams + fineEntryPressure_ = GET_RUNTIME_PARAM(TypeTag, Scalar, SpatialParams.EntryPressureFine); + coarseEntryPressure_ = GET_RUNTIME_PARAM(TypeTag, Scalar, SpatialParams.EntryPressureCoarse); + + // heat conductivity of granite + lambdaSolid_ = 2.8; + + // residual saturations + fineMaterialParams_.setSwr(0.2); + fineMaterialParams_.setSnr(0.0); + coarseMaterialParams_.setSwr(0.2); + coarseMaterialParams_.setSnr(0.0); + + // parameters for the Brooks-Corey law + fineMaterialParams_.setPe(fineEntryPressure_); + coarseMaterialParams_.setPe(coarseEntryPressure_); + fineMaterialParams_.setLambda(2.0); + coarseMaterialParams_.setLambda(2.0); + } + + /*! + * \brief Returns the intrinsic permeability tensor \f$[m^2]\f$ + * + * \param element The finite element + * \param fvGeometry The finite volume geometry of the element + * \param scvIdx The local index of the sub-control volume + */ + const Scalar intrinsicPermeability(const Element &element, + const FVElementGeometry &fvGeometry, + const int scvIdx) const + { + const GlobalPosition &globalPos = fvGeometry.subContVol[scvIdx].global; + if (isFineMaterial_(globalPos)) + return fineK_; + return coarseK_; + } + + /*! + * \brief Returns the porosity \f$[-]\f$ + * + * \param element The finite element + * \param fvGeometry The finite volume geometry of the element + * \param scvIdx The local index of the sub-control volume + */ + Scalar porosity(const Element &element, + const FVElementGeometry &fvGeometry, + const int scvIdx) const + { + const GlobalPosition &globalPos = fvGeometry.subContVol[scvIdx].global; + if (isFineMaterial_(globalPos)) + return finePorosity_; + return coarsePorosity_; + } + + + /*! + * \brief Returns the parameter object for the capillary-pressure/ + * saturation material law + * + * \param element The finite element + * \param fvGeometry The finite volume geometry of the element + * \param scvIdx The local index of the sub-control volume + */ + const MaterialLawParams& materialLawParams(const Element &element, + const FVElementGeometry &fvGeometry, + const int scvIdx) const + { + const GlobalPosition &globalPos = fvGeometry.subContVol[scvIdx].global; + if (isFineMaterial_(globalPos)) + return fineMaterialParams_; + return coarseMaterialParams_; + } + + /*! + * These parameters are only needed for nonisothermal models. Comment them in if you want to implement the 2pni model. + */ + + /*! + * \brief Returns the heat capacity \f$[J / (kg K)]\f$ of the rock matrix. + * + * This is only required for non-isothermal models. + * + * \param element The finite element + * \param fvGeometry The finite volume geometry + * \param scvIdx The local index of the sub-control volume + */ +// Scalar solidHeatCapacity(const Element &element, +// const FVElementGeometry &fvGeometry, +// const int scvIdx) const +// { +// return 790; // specific heat capacity of granite [J / (kg K)] +// } + + /*! + * \brief Returns the mass density \f$[kg / m^3]\f$ of the rock matrix. + * + * This is only required for non-isothermal models. + * + * \param element The finite element + * \param fvGeometry The finite volume geometry + * \param scvIdx The local index of the sub-control volume + */ +// Scalar solidDensity(const Element &element, +// const FVElementGeometry &fvGeometry, +// const int scvIdx) const +// { +// return 2700; // density of granite [kg/m^3] +// } + + /*! + * \brief Returns the thermal conductivity \f$\mathrm{[W/(m K)]}\f$ of the solid + * + * This is only required for non-isothermal models. + * + * \param element The finite element + * \param fvGeometry The finite volume geometry of the element + * \param scvIdx The local index of the sub-control volume + */ +// Scalar solidThermalConductivity(const Element &element, +// const FVElementGeometry &fvGeometry, +// const int scvIdx) const +// { +// return lambdaSolid_; +// } + +private: + bool isFineMaterial_(const GlobalPosition &globalPos) const + { return globalPos[dimWorld-1] > layerBottom_; } + + Scalar fineK_; + Scalar coarseK_; + Scalar layerBottom_; + + Scalar finePorosity_; + Scalar coarsePorosity_; + + Scalar lambdaSolid_; + + Scalar fineEntryPressure_; + Scalar coarseEntryPressure_; + + MaterialLawParams fineMaterialParams_; + MaterialLawParams coarseMaterialParams_; +}; + +} + +#endif -- GitLab From e15ca8506216480d3a10a8e0b62ce1d2989e33eb Mon Sep 17 00:00:00 2001 From: Martin Schneider Date: Thu, 21 Sep 2017 08:06:44 +0200 Subject: [PATCH 11/42] Add ex4 --- tutorial/ex4/README.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 tutorial/ex4/README.md diff --git a/tutorial/ex4/README.md b/tutorial/ex4/README.md new file mode 100644 index 0000000000..6c6c46524e --- /dev/null +++ b/tutorial/ex4/README.md @@ -0,0 +1,18 @@ +# Exercise #4 (DuMuX course) + +This exercise describes how to create a new DuMuX module +and how to create a corresponding gitlab project. + +## Create new DuMuX module +------------------ + +### 1. Execute the following command (bash environment): +```bash +$ ./dune-common/bin/duneproject +``` +Follow the introductions and specify +* Name of your module, e.g. dumux-ex +* Module dependency, which is dumux + +### 2. Run dunecontrol +here you can use --only=Module-Name -- GitLab From 0baa50489bbb64731fed4306f90e56398893f9ac Mon Sep 17 00:00:00 2001 From: Martin Schneider Date: Thu, 21 Sep 2017 08:40:59 +0200 Subject: [PATCH 12/42] Update of README --- tutorial/ex4/README.md | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/tutorial/ex4/README.md b/tutorial/ex4/README.md index 6c6c46524e..6ac7b5946e 100644 --- a/tutorial/ex4/README.md +++ b/tutorial/ex4/README.md @@ -4,7 +4,6 @@ This exercise describes how to create a new DuMuX module and how to create a corresponding gitlab project. ## Create new DuMuX module ------------------- ### 1. Execute the following command (bash environment): ```bash @@ -15,4 +14,29 @@ Follow the introductions and specify * Module dependency, which is dumux ### 2. Run dunecontrol -here you can use --only=Module-Name +here you can use `--only=Module-Name` + + +## Create a new test case within your new DuMuX module + +### 1. Create a new folder (in your module folder), e.g. appl + +### 2. Copy some test case from the dumux module, e.g. test_box1p + +### 3. Incorporate this test case into your cmake files + +### 4. Re-run **dunecontrol** + +### 5. Execute your test problem + + +## Create a new gitlab project + +### 1. Login with your username and password () + +### 2. Click the **New project** button + +### 3. Follow the given instructions for an *existing folder* + +**Important**: Before executing the `git add .` command, you should add your cmake build folder to gitignore. +The easiest way to do so is to just copy the *.gitignore* file from your dumux module into your module path. -- GitLab From 71b681aa8c09e5462873b7bb21c4e1c02a0c05d0 Mon Sep 17 00:00:00 2001 From: Martin Schneider Date: Thu, 21 Sep 2017 08:44:21 +0200 Subject: [PATCH 13/42] Update README.md --- tutorial/ex4/README.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tutorial/ex4/README.md b/tutorial/ex4/README.md index 6ac7b5946e..2832c96cbc 100644 --- a/tutorial/ex4/README.md +++ b/tutorial/ex4/README.md @@ -19,24 +19,24 @@ here you can use `--only=Module-Name` ## Create a new test case within your new DuMuX module -### 1. Create a new folder (in your module folder), e.g. appl +* Create a new folder (in your module folder), e.g. appl -### 2. Copy some test case from the dumux module, e.g. test_box1p +* Copy some test case from the dumux module, e.g. test_box1p -### 3. Incorporate this test case into your cmake files +* Incorporate this test case into your cmake files -### 4. Re-run **dunecontrol** +* Re-run **dunecontrol** -### 5. Execute your test problem +* Execute your test problem ## Create a new gitlab project -### 1. Login with your username and password () +* Login with your username and password () -### 2. Click the **New project** button +* Click the **New project** button -### 3. Follow the given instructions for an *existing folder* +* Follow the given instructions for an *existing folder* **Important**: Before executing the `git add .` command, you should add your cmake build folder to gitignore. The easiest way to do so is to just copy the *.gitignore* file from your dumux module into your module path. -- GitLab From c8cc2702e1c037f6dbebe4ea528ce986ec121622 Mon Sep 17 00:00:00 2001 From: DennisGlaeser Date: Wed, 20 Sep 2017 20:16:33 +0200 Subject: [PATCH 14/42] [tutorial] implement first draft of exercise 3 --- tutorial/ex3/CMakeLists.txt | 11 + .../h2omycompressiblecomponent.hh | 74 +++ .../ex3/components/mycompressiblecomponent.hh | 164 +++++++ .../components/myincompressiblecomponent.hh | 164 +++++++ .../ex3/components/plotdensityfunction.py | 19 + tutorial/ex3/ex3_a.cc | 49 ++ tutorial/ex3/ex3_a.input | 10 + tutorial/ex3/ex3_a_problem.hh | 256 ++++++++++ tutorial/ex3/ex3_b.cc | 49 ++ tutorial/ex3/ex3_b.input | 10 + tutorial/ex3/ex3_b_problem.hh | 237 +++++++++ .../h2omycompressiblecomponent.hh | 458 ++++++++++++++++++ tutorial/ex3/spatialparams.hh | 196 ++++++++ 13 files changed, 1697 insertions(+) create mode 100644 tutorial/ex3/CMakeLists.txt create mode 100644 tutorial/ex3/binarycoefficients/h2omycompressiblecomponent.hh create mode 100644 tutorial/ex3/components/mycompressiblecomponent.hh create mode 100644 tutorial/ex3/components/myincompressiblecomponent.hh create mode 100644 tutorial/ex3/components/plotdensityfunction.py create mode 100644 tutorial/ex3/ex3_a.cc create mode 100644 tutorial/ex3/ex3_a.input create mode 100644 tutorial/ex3/ex3_a_problem.hh create mode 100644 tutorial/ex3/ex3_b.cc create mode 100644 tutorial/ex3/ex3_b.input create mode 100644 tutorial/ex3/ex3_b_problem.hh create mode 100644 tutorial/ex3/fluidsystems/h2omycompressiblecomponent.hh create mode 100644 tutorial/ex3/spatialparams.hh diff --git a/tutorial/ex3/CMakeLists.txt b/tutorial/ex3/CMakeLists.txt new file mode 100644 index 0000000000..aa345e72bf --- /dev/null +++ b/tutorial/ex3/CMakeLists.txt @@ -0,0 +1,11 @@ +add_input_file_links() + +add_dumux_test(ex3_a ex3_a ex3_a.cc ${CMAKE_CURRENT_BINARY_DIR}/exercise3) +add_dumux_test(ex3_b ex3_b ex3_b.cc ${CMAKE_CURRENT_BINARY_DIR}/exercise3) + +#install sources +install(FILES +exercise3.cc +exercise3_problem.hh +exercise3_spatialparams.hh +DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/dumux/tutorial/material_exercise) diff --git a/tutorial/ex3/binarycoefficients/h2omycompressiblecomponent.hh b/tutorial/ex3/binarycoefficients/h2omycompressiblecomponent.hh new file mode 100644 index 0000000000..843a69a675 --- /dev/null +++ b/tutorial/ex3/binarycoefficients/h2omycompressiblecomponent.hh @@ -0,0 +1,74 @@ +// -*- 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 Binary coefficients for water and a ficticious component implemented in tutorial exercise 3a. + */ +#ifndef DUMUX_BINARY_COEFF_H2O_MYCOMPRESSIBLECOMPONENT_HH +#define DUMUX_BINARY_COEFF_H2O_MYCOMPRESSIBLECOMPONENT_HH + +namespace Dumux +{ +namespace BinaryCoeff +{ + +/*! + * \brief Binary coefficients for water and a ficticious component implemented in tutorial exercise 3a + * The implementation of the missing methods in this file is part of exercise 3b. + */ +class H2O_MyCompressibleComponent +{ +public: + /*! + * \brief Henry coefficient \f$[N/m^2]\f$ for the fictitous component in liquid water. + */ + template + static Scalar henryMyCompressibleComponentInWater(Scalar temperature) + { + Scalar dumuxH = 1.5e-1 / 101.325; // unit [(mol/m^3)/Pa] + dumuxH *= 18.02e-6; //multiplied by molar volume of reference phase = water + return 1.0/dumuxH; // [Pa] + } + + /*! + * \brief Henry coefficient \f$[N/m^2]\f$ for water in the ficticious component. + */ + template + static Scalar henryWaterInMyCompressibleComponent(Scalar temperature) + { + // arbitrary + return 1.0e8; // [Pa] + } + + /*! + * \brief Diffusion coefficient [m^2/s] for my ficticious component in liquid water or vice versa. + */ + template + static Scalar liquidDiffCoeff(Scalar temperature, Scalar pressure) + { + // arbitrary + return 1.e-9; + } +}; + +} +} // end namespace + +#endif diff --git a/tutorial/ex3/components/mycompressiblecomponent.hh b/tutorial/ex3/components/mycompressiblecomponent.hh new file mode 100644 index 0000000000..44db2b6326 --- /dev/null +++ b/tutorial/ex3/components/mycompressiblecomponent.hh @@ -0,0 +1,164 @@ +// -*- 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 + * \ingroup Components + * \brief A ficitious component to be implemented in exercise 3. + */ +#ifndef DUMUX_MYCOMPRESSIBLECOMPONENT_HH +#define DUMUX_MYCOMPRESSIBLECOMPONENT_HH + +#include +#include + + +namespace Dumux +{ +/*! + * \ingroup Components + * \brief A ficitious component to be implemented in exercise 3. + * + * \tparam Scalar The type used for scalar values + */ +template +class MyCompressibleComponent : public Component > +{ + +public: + /*! + * \brief A human readable name for MyCompressibleComponent. + */ + static std::string name() + { return "MyCompressibleComponent"; } + + /*! + * \brief The molar mass in \f$\mathrm{[kg/mol]}\f$ of MyCompressibleComponent. + */ + static Scalar molarMass() + { + return 131.39e-3; // [kg/mol] + } + + /*! + * \brief Returns the critical temperature \f$\mathrm{[K]}\f$ of MyCompressibleComponent. + */ + static Scalar criticalTemperature() + { + DUNE_THROW(Dune::NotImplemented, "criticalTemperature for MyCompressibleComponent"); + } + + /*! + * \brief Returns the critical pressure \f$\mathrm{[Pa]}\f$ of MyCompressibleComponent. + */ + static Scalar criticalPressure() + { + DUNE_THROW(Dune::NotImplemented, "criticalPressure for MyCompressibleComponent"); + } + + /*! + * \brief Returns the temperature \f$\mathrm{[K]}\f$ at MyCompressibleComponent's triple point. + */ + static Scalar tripleTemperature() + { + DUNE_THROW(Dune::NotImplemented, "tripleTemperature for MyCompressibleComponent"); + } + + /*! + * \brief Returns the pressure \f$\mathrm{[Pa]}\f$ at MyCompressibleComponent's triple point. + */ + static Scalar triplePressure() + { + DUNE_THROW(Dune::NotImplemented, "triplePressure for MyCompressibleComponent"); + } + + /*! + * \brief The vapor pressure in \f$\mathrm{[Pa]}\f$ of pure MyCompressibleComponent + * at a given temperature. + * + * \param T temperature of component in \f$\mathrm{[K]}\f$ + */ + static Scalar vaporPressure(Scalar T) + { + return 3900; // [Pa] (at 20C) + } + + /*! + * \brief Returns true if the gas phase is assumed to be compressible + */ + static bool gasIsCompressible() + { return true; } + + /*! + * \brief Returns true if the liquid phase is assumed to be compressible + */ + static bool liquidIsCompressible() + { return true; } + + /*! + * \brief The density of steam at a given pressure and temperature \f$\mathrm{[kg/m^3]}\f$. + * + * \param temperature temperature of component in \f$\mathrm{[K]}\f$ + * \param pressure pressure of component in \f$\mathrm{[Pa]}\f$ + */ + static Scalar gasDensity(Scalar temperature, Scalar pressure) + { + return IdealGas::density(molarMass(), + temperature, + pressure); + } + + /*! + * \brief Returns true if the gas phase is assumed to be ideal + */ + static bool gasIsIdeal() + { return true; } + + /*! + * TODO: implement the given pressure-dependent relationship for the liquid density + * + * \brief The density of pure TCE at a given pressure and temperature \f$\mathrm{[kg/m^3]}\f$. + * + * \param temperature temperature of component in \f$\mathrm{[K]}\f$ + * \param pressure pressure of component in \f$\mathrm{[Pa]}\f$ + */ + static Scalar liquidDensity(Scalar temperature, Scalar pressure) + { + static const Scalar rho_min = 1440; + static const Scalar rho_max = 1480; + static const Scalar k = 5e-7; + + using std::exp; + return rho_min + (rho_max - rho_min)/(1 + rho_min*exp(-1.0*k*(rho_max - rho_min)*pressure)); // [kg/m^3] + } + + /*! + * \brief The dynamic viscosity \f$\mathrm{[Pa*s]}\f$ of pure TCE. + * + * \param temperature temperature of component in \f$\mathrm{[K]}\f$ + * \param pressure pressure of component in \f$\mathrm{[Pa]}\f$ + */ + static Scalar liquidViscosity(Scalar temperature, Scalar pressure) + { + return 5.7e-4;// [Pa*s] + } +}; + +} // end namespace + +#endif diff --git a/tutorial/ex3/components/myincompressiblecomponent.hh b/tutorial/ex3/components/myincompressiblecomponent.hh new file mode 100644 index 0000000000..33adf654b1 --- /dev/null +++ b/tutorial/ex3/components/myincompressiblecomponent.hh @@ -0,0 +1,164 @@ +// -*- 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 + * \ingroup Components + * \brief A ficitious component to be implemented in tutorial exercise 3. + */ +#ifndef DUMUX_MYINCOMPRESSIBLECOMPONENT_HH +#define DUMUX_MYINCOMPRESSIBLECOMPONENT_HH + +#include +#include + + +namespace Dumux +{ +/*! + * \ingroup Components + * \brief A ficitious component to be implemented in exercise 3. + * + * \tparam Scalar The type used for scalar values + */ +template +class MyIncompressibleComponent : public Component > +{ + + /*! + * TODO: Implement the missing specifications from the given data sheet. + */ + +public: + /*! + * \brief A human readable name for MyIncompressibleComponent. + */ + static std::string name() + { return "MyIncompressibleComponent"; } + + /*! + * TODO + * \brief The molar mass in \f$\mathrm{[kg/mol]}\f$ of MyIncompressibleComponent. + */ + static Scalar molarMass() + { + return 131.39e-3; // [kg/mol] + } + + /*! + * \brief Returns the critical temperature \f$\mathrm{[K]}\f$ of MyIncompressibleComponent. + */ + static Scalar criticalTemperature() + { + DUNE_THROW(Dune::NotImplemented, "criticalTemperature for MyIncompressibleComponent"); + } + + /*! + * \brief Returns the critical pressure \f$\mathrm{[Pa]}\f$ of MyIncompressibleComponent. + */ + static Scalar criticalPressure() + { + DUNE_THROW(Dune::NotImplemented, "criticalPressure for MyIncompressibleComponent"); + } + + /*! + * \brief Returns the temperature \f$\mathrm{[K]}\f$ at MyIncompressibleComponent's triple point. + */ + static Scalar tripleTemperature() + { + DUNE_THROW(Dune::NotImplemented, "tripleTemperature for MyIncompressibleComponent"); + } + + /*! + * \brief Returns the pressure \f$\mathrm{[Pa]}\f$ at MyIncompressibleComponent's triple point. + */ + static Scalar triplePressure() + { + DUNE_THROW(Dune::NotImplemented, "triplePressure for MyIncompressibleComponent"); + } + + /*! + * \brief The vapor pressure in \f$\mathrm{[Pa]}\f$ of pure MyIncompressibleComponent + * at a given temperature. + * + * \param T temperature of component in \f$\mathrm{[K]}\f$ + */ + static Scalar vaporPressure(Scalar T) + { + return 3900; // [Pa] (at 20C) + } + + /*! + * \brief Returns true if the gas phase is assumed to be compressible + */ + static bool gasIsCompressible() + { return true; } + + /*! + * \brief Returns true if the liquid phase is assumed to be compressible + */ + static bool liquidIsCompressible() + { return false; } + + /*! + * \brief The density of steam at a given pressure and temperature \f$\mathrm{[kg/m^3]}\f$. + * + * \param temperature temperature of component in \f$\mathrm{[K]}\f$ + * \param pressure pressure of component in \f$\mathrm{[Pa]}\f$ + */ + static Scalar gasDensity(Scalar temperature, Scalar pressure) + { + return IdealGas::density(molarMass(), + temperature, + pressure); + } + + /*! + * \brief Returns true if the gas phase is assumed to be ideal + */ + static bool gasIsIdeal() + { return true; } + + /*! + * TODO + * \brief The density of pure TCE at a given pressure and temperature \f$\mathrm{[kg/m^3]}\f$. + * + * \param temperature temperature of component in \f$\mathrm{[K]}\f$ + * \param pressure pressure of component in \f$\mathrm{[Pa]}\f$ + */ + static Scalar liquidDensity(Scalar temperature, Scalar pressure) + { + return 1460.0; // [kg/m^3] + } + + /*! + * TODO + * \brief The dynamic viscosity \f$\mathrm{[Pa*s]}\f$ of pure TCE. + * + * \param temperature temperature of component in \f$\mathrm{[K]}\f$ + * \param pressure pressure of component in \f$\mathrm{[Pa]}\f$ + */ + static Scalar liquidViscosity(Scalar temperature, Scalar pressure) + { + return 5.7e-4;// [Pa*s] + } +}; + +} // end namespace + +#endif diff --git a/tutorial/ex3/components/plotdensityfunction.py b/tutorial/ex3/components/plotdensityfunction.py new file mode 100644 index 0000000000..2b25668933 --- /dev/null +++ b/tutorial/ex3/components/plotdensityfunction.py @@ -0,0 +1,19 @@ +#!usr/bin/env python +import numpy as np +import matplotlib.pyplot as plt + +# function to calculate rho dependent on pressure +rho_min = 1440; +rho_max = 1480; +k = 5e-7; + +def rho(p): + return rho_min + (rho_max - rho_min)/(1 + rho_min*np.exp(-1.0*k*(rho_max - rho_min)*p)); + +# sample pressure in range (1e4, 1e7) and compute corresponding densities +p = np.logspace(4, 7, 100) +r = rho(p) + +# plot density vs. pressure +plt.semilogx(p, r) +plt.show() diff --git a/tutorial/ex3/ex3_a.cc b/tutorial/ex3/ex3_a.cc new file mode 100644 index 0000000000..1761630a24 --- /dev/null +++ b/tutorial/ex3/ex3_a.cc @@ -0,0 +1,49 @@ +// -*- 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 Main file of exercise 3. + */ +#include +#include "ex3_a_problem.hh" +#include + +//! Prints a usage/help message if something goes wrong or the user asks for help +void usage(const char *progName, const std::string &errorMsg) +{ + std::cout + << "\nUsage: " << progName << " [options]\n"; + if (errorMsg.size() > 0) + std::cout << errorMsg << "\n"; + std::cout + << "\n" + << "The list of mandatory arguments for this program is:\n" + << "\t-TEnd The end of the simulation [s]\n" + << "\t-DtInitial The initial timestep size [s]\n" + << "\t-Grid.UpperRight The x-/y-coordinates of the grid's upper-right corner [m]\n" + << "\t-Grid.Cells The grid's x-/y-resolution\n" + << "\n"; +} + +int main(int argc, char** argv) +{ + typedef TTAG(ExerciseThreeProblem) TypeTag; + return Dumux::start(argc, argv, usage); +} diff --git a/tutorial/ex3/ex3_a.input b/tutorial/ex3/ex3_a.input new file mode 100644 index 0000000000..ce45509020 --- /dev/null +++ b/tutorial/ex3/ex3_a.input @@ -0,0 +1,10 @@ +[TimeManager] +TEnd = 20000 # duration of the simulation [s] +DtInitial = 10 # initial time step size [s] + +[Problem] +Name = exercise3_a + +[Grid] +UpperRight = 60 60 # x-/y-coordinates of the upper-right corner of the grid [m] +Cells = 60 60 # x-/y-resolution of the grid diff --git a/tutorial/ex3/ex3_a_problem.hh b/tutorial/ex3/ex3_a_problem.hh new file mode 100644 index 0000000000..b4a9ebe147 --- /dev/null +++ b/tutorial/ex3/ex3_a_problem.hh @@ -0,0 +1,256 @@ +// -*- 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 Tutorial problem for a fully coupled twophase box model. + */ +#ifndef DUMUX_EXERCISE_THREE_PROBLEM_HH +#define DUMUX_EXERCISE_THREE_PROBLEM_HH + +// The numerical model +#include + +// The base porous media box problem +#include + +// Spatially dependent parameters +#include "spatialparams.hh" + +// The water component +#include +#include + +// The components that will be created in this exercise +#include "components/myincompressiblecomponent.hh" +#include "components/mycompressiblecomponent.hh" + +// We will only have liquid phases Here +#include + +// The fluid system that is used +#include + +namespace Dumux{ +// Forward declaration of the problem class +template class ExerciseThreeProblem; + +namespace Properties { +// Create a new type tag for the problem +NEW_TYPE_TAG(ExerciseThreeProblem, INHERITS_FROM(BoxTwoP, ExerciseThreeSpatialParams)); + +// Set the "Problem" property +SET_TYPE_PROP(ExerciseThreeProblem, Problem, ExerciseThreeProblem); + +// Set grid and the grid creator to be used +#if HAVE_DUNE_ALUGRID +SET_TYPE_PROP(ExerciseThreeProblem, Grid, Dune::ALUGrid); +#elif HAVE_UG +SET_TYPE_PROP(ExerciseThreeProblem, Grid, Dune::UGGrid<2>); +#else +SET_TYPE_PROP(ExerciseThreeProblem, Grid, Dune::YaspGrid<2>); +#endif // HAVE_DUNE_ALUGRID + +// we use the immiscible fluid system here +SET_PROP(ExerciseThreeProblem, FluidSystem) +{ +private: + typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; + typedef TabulatedComponent> TabulatedH2O; + typedef typename FluidSystems::LiquidPhase WettingPhase; + + /*! + * TODO: define the liquid phase of your component as the non-wetting phase + * Solution: Uncomment first line and comment second line for exercise 3a + * Uncomment second line and comment first line for exercise 3b + */ + // typedef typename FluidSystems::LiquidPhase > NonWettingPhase; + typedef typename FluidSystems::LiquidPhase > NonWettingPhase; + +public: + typedef typename FluidSystems::TwoPImmiscible type; +}; + +// Disable gravity +SET_BOOL_PROP(ExerciseThreeProblem, ProblemEnableGravity, true); +} + +/*! + * \ingroup TwoPBoxModel + * + * \brief Tutorial problem for a fully coupled twophase box model. + */ +template +class ExerciseThreeProblem : public ImplicitPorousMediaProblem +{ + typedef ImplicitPorousMediaProblem ParentType; + typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; + typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; + + // Grid dimension + enum { dim = GridView::dimension, + dimWorld = GridView::dimensionworld + }; + + // Types from DUNE-Grid + typedef typename GridView::template Codim<0>::Entity Element; + typedef typename GridView::template Codim::Entity Vertex; + typedef typename GridView::Intersection Intersection; + typedef Dune::FieldVector GlobalPosition; + + // Dumux specific types + typedef typename GET_PROP_TYPE(TypeTag, TimeManager) TimeManager; + typedef typename GET_PROP_TYPE(TypeTag, Indices) Indices; + typedef typename GET_PROP_TYPE(TypeTag, PrimaryVariables) PrimaryVariables; + typedef typename GET_PROP_TYPE(TypeTag, BoundaryTypes) BoundaryTypes; + typedef typename GET_PROP_TYPE(TypeTag, FVElementGeometry) FVElementGeometry; + +public: + ExerciseThreeProblem(TimeManager &timeManager, + const GridView &gridView) + : ParentType(timeManager, gridView) + , eps_(3e-6) + { +#if !(HAVE_DUNE_ALUGRID || HAVE_UG) + std::cout << "If you want to use simplices instead of cubes, install and use dune-ALUGrid or UGGrid." << std::endl; +#endif // !(HAVE_DUNE_ALUGRID || HAVE_UG) + + // initialize the tables for the water properties + std::cout << "Initializing the tables for the water properties" << std::endl; + TabulatedComponent>::init(/*tempMin=*/273.15, + /*tempMax=*/623.15, + /*numTemp=*/100, + /*pMin=*/0.0, + /*pMax=*/20e6, + /*numP=*/200); + + // set the depth of the bottom of the reservoir + depthBOR_ = this->bBoxMax()[dimWorld-1]; + } + + //! Specifies the problem name. This is used as a prefix for files + //! generated by the simulation. + std::string name() const + { + static const std::string name = GET_RUNTIME_PARAM_FROM_GROUP(TypeTag, std::string, Problem, Name); + return name; + } + + //! Returns true if a restart file should be written. + bool shouldWriteRestartFile() const + { return false; } + + //! Returns true if the current solution should be written to disk + //! as a VTK file + bool shouldWriteOutput() const + { + return this->timeManager().timeStepIndex() > 0 && + this->timeManager().timeStepIndex() % 1 == 0; + } + + //! Returns the temperature within a finite volume. We use constant + //! 10 degrees Celsius. + Scalar temperature() const + { return 283.15; } + + //! Specifies which kind of boundary condition should be used for + //! which equation for a finite volume on the boundary. + void boundaryTypes(BoundaryTypes &bcTypes, const Vertex &vertex) const + { + const GlobalPosition &globalPos = vertex.geometry().center(); + + // Dirichlet conditions on left & right boundary + if (globalPos[0] < eps_ || globalPos[0] > this->bBoxMax()[0] - eps_) + bcTypes.setAllDirichlet(); + else // neuman for the remaining boundaries + bcTypes.setAllNeumann(); + + } + + //! Evaluates the Dirichlet boundary conditions for a finite volume + //! on the grid boundary. Here, the 'values' parameter stores + //! primary variables. + void dirichlet(PrimaryVariables &values, const Vertex &vertex) const + { + const auto globalPos = vertex.geometry().center(); + values[Indices::pwIdx] = 200.0e3 + 9.81*1000*(depthBOR_ - globalPos[dimWorld-1]); // 200 kPa = 2 bar + values[Indices::snIdx] = 0.0; // 0 % oil saturation on left boundary + } + + //! Evaluates the boundary conditions for a Neumann boundary + //! segment. Here, the 'values' parameter stores the mass flux in + //! [kg/(m^2 * s)] in normal direction of each phase. Negative + //! values mean influx. + void neumann(PrimaryVariables &values, + const Element &element, + const FVElementGeometry &fvGeometry, + const Intersection &intersection, + int scvIdx, + int boundaryFaceIdx) const + { + const GlobalPosition &globalPos = + fvGeometry.boundaryFace[boundaryFaceIdx].ipGlobal; + Scalar up = this->bBoxMax()[dimWorld-1]; + // extraction of oil on the right boundary for approx. 1.e6 seconds + if (globalPos[dimWorld-1] > up - eps_ && globalPos[0] > 20 && globalPos[0] < 40) { + // oil outflux of 30 g/(m * s) on the right boundary. + values[Indices::contiWEqIdx] = 0; + values[Indices::contiNEqIdx] = -3e-2; + } else { + // no-flow on the remaining Neumann-boundaries. + values[Indices::contiWEqIdx] = 0; + values[Indices::contiNEqIdx] = 0; + } + } + + //! Evaluates the initial value for a control volume. For this + //! method, the 'values' parameter stores primary variables. + void initial(PrimaryVariables &values, + const Element &element, + const FVElementGeometry &fvGeometry, + int scvIdx) const + { + const auto globalPos = fvGeometry.subContVol[scvIdx].global; + values[Indices::pwIdx] = 200.0e3 + 9.81*1000*(depthBOR_ - globalPos[dimWorld-1]); // 200 kPa = 2 bar + values[Indices::snIdx] = 0.0; + } + + //! Evaluates the source term for all phases within a given + //! sub-control-volume. In this case, the 'values' parameter + //! stores the rate mass generated or annihilated per volume unit + //! in [kg / (m^3 * s)]. Positive values mean that mass is created. + void source(PrimaryVariables &values, + const Element &element, + const FVElementGeometry &fvGeometry, + int scvIdx) const + { + values[Indices::contiWEqIdx] = 0.0; + values[Indices::contiNEqIdx]= 0.0; + } + +private: + // small epsilon value + Scalar eps_; + + // depth at the bottom of the reservoir + Scalar depthBOR_; +}; +} + +#endif diff --git a/tutorial/ex3/ex3_b.cc b/tutorial/ex3/ex3_b.cc new file mode 100644 index 0000000000..1a548af812 --- /dev/null +++ b/tutorial/ex3/ex3_b.cc @@ -0,0 +1,49 @@ +// -*- 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 Main file of exercise 3. + */ +#include +#include "ex3_b_problem.hh" +#include + +//! Prints a usage/help message if something goes wrong or the user asks for help +void usage(const char *progName, const std::string &errorMsg) +{ + std::cout + << "\nUsage: " << progName << " [options]\n"; + if (errorMsg.size() > 0) + std::cout << errorMsg << "\n"; + std::cout + << "\n" + << "The list of mandatory arguments for this program is:\n" + << "\t-TEnd The end of the simulation [s]\n" + << "\t-DtInitial The initial timestep size [s]\n" + << "\t-Grid.UpperRight The x-/y-coordinates of the grid's upper-right corner [m]\n" + << "\t-Grid.Cells The grid's x-/y-resolution\n" + << "\n"; +} + +int main(int argc, char** argv) +{ + typedef TTAG(ExerciseThreeProblem) TypeTag; + return Dumux::start(argc, argv, usage); +} diff --git a/tutorial/ex3/ex3_b.input b/tutorial/ex3/ex3_b.input new file mode 100644 index 0000000000..16c1b6a5ec --- /dev/null +++ b/tutorial/ex3/ex3_b.input @@ -0,0 +1,10 @@ +[TimeManager] +TEnd = 20000 # duration of the simulation [s] +DtInitial = 10 # initial time step size [s] + +[Problem] +Name = exercise3_b + +[Grid] +UpperRight = 60 60 # x-/y-coordinates of the upper-right corner of the grid [m] +Cells = 60 60 # x-/y-resolution of the grid diff --git a/tutorial/ex3/ex3_b_problem.hh b/tutorial/ex3/ex3_b_problem.hh new file mode 100644 index 0000000000..a6ef025781 --- /dev/null +++ b/tutorial/ex3/ex3_b_problem.hh @@ -0,0 +1,237 @@ +// -*- 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 Tutorial problem for a fully coupled twophase box model. + */ +#ifndef DUMUX_EXERCISE_THREE_PROBLEM_HH +#define DUMUX_EXERCISE_THREE_PROBLEM_HH + +// The numerical model +#include + +// The base porous media box problem +#include + +// Spatially dependent parameters +#include "spatialparams.hh" + +// The fluid system that is created in this exercise +#include "fluidsystems/h2omycompressiblecomponent.hh" + +namespace Dumux{ +// Forward declaration of the problem class +template class ExerciseThreeProblem; + +namespace Properties { +// Create a new type tag for the problem +NEW_TYPE_TAG(ExerciseThreeProblem, INHERITS_FROM(BoxTwoPTwoC, ExerciseThreeSpatialParams)); + +// Set the "Problem" property +SET_TYPE_PROP(ExerciseThreeProblem, Problem, ExerciseThreeProblem); + +// Set grid and the grid creator to be used +#if HAVE_DUNE_ALUGRID +SET_TYPE_PROP(ExerciseThreeProblem, Grid, Dune::ALUGrid); +#elif HAVE_UG +SET_TYPE_PROP(ExerciseThreeProblem, Grid, Dune::UGGrid<2>); +#else +SET_TYPE_PROP(ExerciseThreeProblem, Grid, Dune::YaspGrid<2>); +#endif // HAVE_DUNE_ALUGRID + + // The fluid system property +SET_PROP(ExerciseThreeProblem, FluidSystem) +{ +private: + typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; +public: + /*! + * TODO: set the fluid system created in this exercise as the property + */ + typedef FluidSystems::H2OMyCompressibleComponent type; +}; + +// Disable gravity +SET_BOOL_PROP(ExerciseThreeProblem, ProblemEnableGravity, true); +} + +/*! + * \ingroup TwoPBoxModel + * + * \brief Tutorial problem for a fully coupled twophase box model. + */ +template +class ExerciseThreeProblem : public ImplicitPorousMediaProblem +{ + typedef ImplicitPorousMediaProblem ParentType; + typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; + typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; + + // Grid dimension + enum { dim = GridView::dimension, + dimWorld = GridView::dimensionworld + }; + + // Types from DUNE-Grid + typedef typename GridView::template Codim<0>::Entity Element; + typedef typename GridView::template Codim::Entity Vertex; + typedef typename GridView::Intersection Intersection; + typedef Dune::FieldVector GlobalPosition; + + // Dumux specific types + typedef typename GET_PROP_TYPE(TypeTag, TimeManager) TimeManager; + typedef typename GET_PROP_TYPE(TypeTag, Indices) Indices; + typedef typename GET_PROP_TYPE(TypeTag, PrimaryVariables) PrimaryVariables; + typedef typename GET_PROP_TYPE(TypeTag, BoundaryTypes) BoundaryTypes; + typedef typename GET_PROP_TYPE(TypeTag, FVElementGeometry) FVElementGeometry; + typedef typename GET_PROP_TYPE(TypeTag, FluidSystem) FluidSystem; + +public: + ExerciseThreeProblem(TimeManager &timeManager, + const GridView &gridView) + : ParentType(timeManager, gridView) + , eps_(3e-6) + { +#if !(HAVE_DUNE_ALUGRID || HAVE_UG) + std::cout << "If you want to use simplices instead of cubes, install and use dune-ALUGrid or UGGrid." << std::endl; +#endif // !(HAVE_DUNE_ALUGRID || HAVE_UG) + + // initialize the fluid system + FluidSystem::init(); + + // set the depth of the bottom of the reservoir + depthBOR_ = this->bBoxMax()[dimWorld-1]; + } + + //! Specifies the problem name. This is used as a prefix for files + //! generated by the simulation. + std::string name() const + { + static const std::string name = GET_RUNTIME_PARAM_FROM_GROUP(TypeTag, std::string, Problem, Name); + return name; + } + + //! Returns true if a restart file should be written. + bool shouldWriteRestartFile() const + { return false; } + + //! Returns true if the current solution should be written to disk + //! as a VTK file + bool shouldWriteOutput() const + { + return this->timeManager().timeStepIndex() > 0 && + this->timeManager().timeStepIndex() % 1 == 0; + } + + //! Returns the temperature within a finite volume. We use constant + //! 10 degrees Celsius. + Scalar temperature() const + { return 283.15; } + + //! Specifies which kind of boundary condition should be used for + //! which equation for a finite volume on the boundary. + void boundaryTypes(BoundaryTypes &bcTypes, const Vertex &vertex) const + { + const GlobalPosition &globalPos = vertex.geometry().center(); + + // Dirichlet conditions on left & right boundary + if (globalPos[0] < eps_ || globalPos[0] > this->bBoxMax()[0] - eps_) + bcTypes.setAllDirichlet(); + else // neuman for the remaining boundaries + bcTypes.setAllNeumann(); + + } + + //! Evaluates the Dirichlet boundary conditions for a finite volume + //! on the grid boundary. Here, the 'values' parameter stores + //! primary variables. + void dirichlet(PrimaryVariables &values, const Vertex &vertex) const + { + const auto globalPos = vertex.geometry().center(); + values[Indices::pressureIdx] = 200.0e3 + 9.81*1000*(depthBOR_ - globalPos[dimWorld-1]); + values[Indices::switchIdx] = 0.0; // 0 % oil saturation on left boundary + } + + //! Evaluates the boundary conditions for a Neumann boundary + //! segment. Here, the 'values' parameter stores the mass flux in + //! [kg/(m^2 * s)] in normal direction of each phase. Negative + //! values mean influx. + void neumann(PrimaryVariables &values, + const Element &element, + const FVElementGeometry &fvGeometry, + const Intersection &intersection, + int scvIdx, + int boundaryFaceIdx) const + { + const GlobalPosition &globalPos = + fvGeometry.boundaryFace[boundaryFaceIdx].ipGlobal; + Scalar up = this->bBoxMax()[dimWorld-1]; + // extraction of oil on the right boundary for approx. 1.e6 seconds + if (globalPos[dimWorld-1] > up - eps_ && globalPos[0] > 20 && globalPos[0] < 40) { + // oil outflux of 30 g/(m * s) on the right boundary. + // we solve for the mole balance, so we have to divide by the molar mass + values[Indices::contiWEqIdx] = 0; + values[Indices::contiNEqIdx] = -3e-2/FluidSystem::MyCompressibleComponent::molarMass(); + } else { + // no-flow on the remaining Neumann-boundaries. + values[Indices::contiWEqIdx] = 0; + values[Indices::contiNEqIdx] = 0; + } + } + + //! Evaluates the initial value for a control volume. For this + //! method, the 'values' parameter stores primary variables. + void initial(PrimaryVariables &values, + const Element &element, + const FVElementGeometry &fvGeometry, + int scvIdx) const + { + const auto globalPos = fvGeometry.subContVol[scvIdx].global; + values[Indices::pressureIdx] = 200.0e3 + 9.81*1000*(depthBOR_ - globalPos[dimWorld-1]); // 200 kPa = 2 bar + values[Indices::switchIdx] = 0.0; + } + + //! Evaluates the source term for all phases within a given + //! sub-control-volume. In this case, the 'values' parameter + //! stores the rate mass generated or annihilated per volume unit + //! in [kg / (m^3 * s)]. Positive values mean that mass is created. + void source(PrimaryVariables &values, + const Element &element, + const FVElementGeometry &fvGeometry, + int scvIdx) const + { + values[Indices::contiWEqIdx] = 0.0; + values[Indices::contiNEqIdx]= 0.0; + } + + //! Evaluates the initial phase presence + int initialPhasePresenceAtPos(const GlobalPosition &globalPos) const + { return Indices::wPhaseOnly; } + +private: + // small epsilon value + Scalar eps_; + + // depth at the bottom of the reservoir + Scalar depthBOR_; +}; +} + +#endif diff --git a/tutorial/ex3/fluidsystems/h2omycompressiblecomponent.hh b/tutorial/ex3/fluidsystems/h2omycompressiblecomponent.hh new file mode 100644 index 0000000000..d29d3758f8 --- /dev/null +++ b/tutorial/ex3/fluidsystems/h2omycompressiblecomponent.hh @@ -0,0 +1,458 @@ +// -*- 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 A fluid system with water and a ficitious component, which is to be + * implemented in tutorial exercise 3a, as phases and components. This + * fluid system is to be implemented in exercise 3b. + */ +#ifndef DUMUX_H2O_MYCOMPRESSIBLECOMPONENT_FLUID_SYSTEM_HH +#define DUMUX_H2O_MYCOMPRESSIBLECOMPONENT_FLUID_SYSTEM_HH + +#include +#include + +#include + +// the ficitious component that was created in exercise 3a +#include + +// the binary coefficients corresponding to this fluid system +#include + +namespace Dumux +{ +namespace FluidSystems +{ + +/*! + * \brief A compositional fluid consisting of two liquid phases, + * which are water and a ficitious component from tutorial exercise 3a. + */ +template > > +class H2OMyCompressibleComponent + : public BaseFluidSystem< Scalar, H2OMyCompressibleComponent > +{ + typedef H2OMyCompressibleComponent ThisType; + typedef BaseFluidSystem Base; + +public: + typedef Dumux::MyCompressibleComponent MyCompressibleComponent; + typedef H2OType H2O; + + static const int numPhases = 2; + static const int numComponents = 2; + + static const int wPhaseIdx = 0; // index of the water phase + static const int nPhaseIdx = 1; // index of the NAPL phase + + static const int H2OIdx = 0; + static const int NAPLIdx = 1; + + // export component indices to indicate the main component + // of the corresponding phase at atmospheric pressure 1 bar + // and room temperature 20°C: + static const int wCompIdx = H2OIdx; + static const int nCompIdx = NAPLIdx; + + /*! + * \brief Initialize the fluid system's static parameters generically + * + * If a tabulated H2O component is used, we do our best to create + * tables that always work. + */ + static void init() + { + init(/*tempMin=*/273.15, + /*tempMax=*/623.15, + /*numTemp=*/100, + /*pMin=*/0.0, + /*pMax=*/20e6, + /*numP=*/200); + } + + /*! + * \brief Initialize the fluid system's static parameters using + * problem specific temperature and pressure ranges + * + * \param tempMin The minimum temperature used for tabulation of water [K] + * \param tempMax The maximum temperature used for tabulation of water [K] + * \param nTemp The number of ticks on the temperature axis of the table of water + * \param pressMin The minimum pressure used for tabulation of water [Pa] + * \param pressMax The maximum pressure used for tabulation of water [Pa] + * \param nPress The number of ticks on the pressure axis of the table of water + */ + static void init(Scalar tempMin, Scalar tempMax, unsigned nTemp, + Scalar pressMin, Scalar pressMax, unsigned nPress) + { + if (H2O::isTabulated) { + std::cout << "Initializing tables for the H2O fluid properties (" + << nTemp*nPress + << " entries).\n"; + + H2O::init(tempMin, tempMax, nTemp, + pressMin, pressMax, nPress); + } + } + + + /*! + * \brief Return whether a phase is liquid + * + * \param phaseIdx The index of the fluid phase to consider + */ + static bool isLiquid(int phaseIdx) + { + assert(0 <= phaseIdx && phaseIdx < numPhases); + return true; + } + + static bool isIdealGas(int phaseIdx) + { return H2O::gasIsIdeal() && MyCompressibleComponent::gasIsIdeal(); } + + /*! + * \brief Returns true if and only if a fluid phase is assumed to + * be an ideal mixture. + * + * We define an ideal mixture as a fluid phase where the fugacity + * coefficients of all components times the pressure of the phase + * are indepent on the fluid composition. This assumtion is true + * if Henry's law and Raoult's law apply. If you are unsure what + * this function should return, it is safe to return false. The + * only damage done will be (slightly) increased computation times + * in some cases. + * + * \param phaseIdx The index of the fluid phase to consider + */ + static bool isIdealMixture(int phaseIdx) + { + assert(0 <= phaseIdx && phaseIdx < numPhases); + return true; + } + + /*! + * \brief Returns true if and only if a fluid phase is assumed to + * be compressible. + * + * Compressible means that the partial derivative of the density + * to the fluid pressure is always larger than zero. + * + * \param phaseIdx The index of the fluid phase to consider + */ + static bool isCompressible(int phaseIdx) + { + assert(0 <= phaseIdx && phaseIdx < numPhases); + if (phaseIdx == wPhaseIdx) + // the water component decides for the water phase... + return H2O::liquidIsCompressible(); + + // the NAPL component decides for the napl phase... + return MyCompressibleComponent::liquidIsCompressible(); + } + + /*! + * \brief Return the human readable name of a phase (used in indices) + */ + static std::string phaseName(int phaseIdx) + { + switch (phaseIdx) { + case wPhaseIdx: return "w"; + case nPhaseIdx: return "n"; + }; + DUNE_THROW(Dune::InvalidStateException, "Invalid phase index " << phaseIdx); + } + + /*! + * \brief Return the human readable name of a component (used in indices) + */ + static std::string componentName(int compIdx) + { + switch (compIdx) { + case H2OIdx: return H2O::name(); + case NAPLIdx: return MyCompressibleComponent::name(); + }; + DUNE_THROW(Dune::InvalidStateException, "Invalid component index " << compIdx); + } + + /*! + * \brief Return the molar mass of a component in [kg/mol]. + */ + static Scalar molarMass(int compIdx) + { + switch (compIdx) { + case H2OIdx: return H2O::molarMass(); + case NAPLIdx: return MyCompressibleComponent::molarMass(); + }; + DUNE_THROW(Dune::InvalidStateException, "Invalid component index " << compIdx); + } + + /*! + * \brief Given all mole fractions in a phase, return the phase + * density [kg/m^3]. + */ + using Base::density; + template + static Scalar density(const FluidState &fluidState, int phaseIdx) + { + assert(0 <= phaseIdx && phaseIdx < numPhases); + if (phaseIdx == wPhaseIdx) { + // See: doctoral thesis of Steffen Ochs 2007 + // Steam injection into saturated porous media : process analysis including experimental and numerical investigations + // http://elib.uni-stuttgart.de/bitstream/11682/271/1/Diss_Ochs_OPUS.pdf + Scalar rholH2O = H2O::liquidDensity(fluidState.temperature(phaseIdx), fluidState.pressure(phaseIdx)); + Scalar clH2O = rholH2O/H2O::molarMass(); + + /*! + * TODO: implement the composition-dependent water density from the exercise sheet. + */ + return + clH2O*(H2O::molarMass()*fluidState.moleFraction(wPhaseIdx, H2OIdx) + + + MyCompressibleComponent::molarMass()*fluidState.moleFraction(wPhaseIdx, NAPLIdx)); + } + else { + // assume the density of the fictious component to be independent of the composition + Scalar pressure = MyCompressibleComponent::liquidIsCompressible()?fluidState.pressure(phaseIdx):1e100; + return MyCompressibleComponent::liquidDensity(fluidState.temperature(phaseIdx), pressure); + } + } + + /*! + * \brief Return the viscosity of a phase. + */ + using Base::viscosity; + template + static Scalar viscosity(const FluidState &fluidState, + int phaseIdx) + { + assert(0 <= phaseIdx && phaseIdx < numPhases); + if (phaseIdx == wPhaseIdx) { + // assume pure water viscosity + return H2O::liquidViscosity(fluidState.temperature(phaseIdx), + fluidState.pressure(phaseIdx)); + } + else { + // assume pure NAPL viscosity + return MyCompressibleComponent::liquidViscosity(fluidState.temperature(phaseIdx), fluidState.pressure(phaseIdx)); + } + } + + using Base::diffusionCoefficient; + template + static Scalar diffusionCoefficient(const FluidState &fluidState, int phaseIdx, int compIdx) + { + DUNE_THROW(Dune::NotImplemented, "Diffusion coefficients"); + } + + /*! + * \brief Given a phase's composition, temperature and pressure, + * return the binary diffusion coefficient \f$\mathrm{[m^2/s]}\f$ for components + * \f$\mathrm{i}\f$ and \f$\mathrm{j}\f$ in this phase. + * \param fluidState The fluid state + * \param paramCache mutable parameters + * \param phaseIdx Index of the fluid phase + * \param compIIdx Index of the component i + * \param compJIdx Index of the component j + */ + using Base::binaryDiffusionCoefficient; + template + static Scalar binaryDiffusionCoefficient(const FluidState &fluidState, + int phaseIdx, + int compIIdx, + int compJIdx) + { + assert(0 <= phaseIdx && phaseIdx < numPhases); + assert(0 <= compIdx && compIdx < numComponents); + + const Scalar T = fluidState.temperature(phaseIdx); + const Scalar p = fluidState.pressure(phaseIdx); + + // we assume the diffusion coefficient to be the same in both phases + return Dumux::BinaryCoeff::H2O_MyCompressibleComponent::liquidDiffCoeff(T, p); + } + + /* Henry coefficients + */ + template + static Scalar henryCoefficient(const FluidState &fluidState, + int phaseIdx, + int compIdx) + { + assert(0 <= phaseIdx && phaseIdx < numPhases); + assert(0 <= compIdx && compIdx < numComponents); + + const Scalar T = fluidState.temperature(phaseIdx); + const Scalar p = fluidState.pressure(phaseIdx); + + if (compIdx == NAPLIdx && phaseIdx == wPhaseIdx) + return Dumux::BinaryCoeff::H2O_MyCompressibleComponent::henryMyCompressibleComponentInWater(T)/p; + + else if (phaseIdx == nPhaseIdx && compIdx == H2OIdx) + return Dumux::BinaryCoeff::H2O_MyCompressibleComponent::henryWaterInMyCompressibleComponent(T)/p; + + else + DUNE_THROW(Dune::InvalidStateException, "non-existent henry coefficient for phase index " << phaseIdx + << " and component index " << compIdx); + } + + using Base::fugacityCoefficient; + /*! + * \brief Returns the fugacity coefficient \f$\mathrm{[-]}\f$ of a component in a + * phase. + * + * In this case, things are actually pretty simple. We have an ideal + * solution. Thus, the fugacity coefficient is 1 in the gas phase + * (fugacity equals the partial pressure of the component in the gas phase + * respectively in the liquid phases it is the inverse of the + * Henry coefficients scaled by pressure + * \param fluidState The fluid state + * \param phaseIdx The index of the phase + * \param compIdx The index of the component + */ + template + static Scalar fugacityCoefficient(const FluidState &fluidState, + int phaseIdx, + int compIdx) + { + assert(0 <= phaseIdx && phaseIdx < numPhases); + assert(0 <= compIdx && compIdx < numComponents); + + Scalar T = fluidState.temperature(phaseIdx); + Scalar p = fluidState.pressure(phaseIdx); + + if (phaseIdx == wPhaseIdx) { + if (compIdx == H2OIdx) + return H2O::vaporPressure(T)/p; + else if (compIdx == NAPLIdx) + return Dumux::BinaryCoeff::H2O_MyCompressibleComponent::henryMyCompressibleComponentInWater(T)/p; + } + + // for the NAPL phase, we assume currently that nothing is + // dissolved. this means that the affinity of the NAPL + // component to the NAPL phase is much higher than for the + // other components, i.e. the fugacity coefficient is much + // smaller. + Scalar phiNapl = MyCompressibleComponent::vaporPressure(T)/p; + if (compIdx == NAPLIdx) + return phiNapl; + else + return 1e6*phiNapl; + } + + template + static Scalar kelvinVaporPressure(const FluidState &fluidState, + const int phaseIdx, + const int compIdx) + { + DUNE_THROW(Dune::NotImplemented, "FluidSystems::H2OMyCompressibleComponent::kelvinVaporPressure()"); + } + + /* partial pressures in the gas phase, taken from saturation vapor pressures + */ + template + static Scalar partialPressureGas(const FluidState &fluidState, int phaseIdx, + int compIdx) + { + assert(0 <= compIdx && compIdx < numComponents); + + const Scalar T = fluidState.temperature(phaseIdx); + if (compIdx == NAPLIdx) + return MyCompressibleComponent::vaporPressure(T); + else if (compIdx == H2OIdx) + return H2O::vaporPressure(T); + else + DUNE_THROW(Dune::InvalidStateException, "non-existent component index " << compIdx); + } + + /* inverse vapor pressures, taken from inverse saturation vapor pressures + */ + template + static Scalar inverseVaporPressureCurve(const FluidState &fluidState, + int phaseIdx, + int compIdx) + { + assert(0 <= compIdx && compIdx < numComponents); + + const Scalar pressure = fluidState.pressure(phaseIdx); + if (compIdx == NAPLIdx) + return MyCompressibleComponent::vaporTemperature(pressure); + else if (compIdx == H2OIdx) + return H2O::vaporTemperature(pressure); + else + DUNE_THROW(Dune::InvalidStateException, "non-existent component index " << compIdx); + } + + + + /*! + * \brief Given all mole fractions in a phase, return the specific + * phase enthalpy [J/kg]. + */ + using Base::enthalpy; + template + static Scalar enthalpy(const FluidState &fluidState, + int phaseIdx) + { + assert(0 <= phaseIdx && phaseIdx < numPhases); + if (phaseIdx == wPhaseIdx) { + return H2O::liquidEnthalpy(fluidState.temperature(phaseIdx), fluidState.pressure(phaseIdx)); + } + else { + return MyCompressibleComponent::liquidEnthalpy(fluidState.temperature(phaseIdx), fluidState.pressure(phaseIdx)); + } + DUNE_THROW(Dune::InvalidStateException, "Invalid phase index " << phaseIdx); + } + + using Base::heatCapacity; + template + static Scalar heatCapacity(const FluidState &fluidState, + int phaseIdx) + { + DUNE_THROW(Dune::NotImplemented, "FluidSystems::H2ONAPL::heatCapacity()"); + } + + using Base::thermalConductivity; + template + static Scalar thermalConductivity(const FluidState &fluidState, + int phaseIdx) + { + assert(0 <= phaseIdx && phaseIdx < numPhases); + + const Scalar temperature = fluidState.temperature(phaseIdx) ; + const Scalar pressure = fluidState.pressure(phaseIdx); + if (phaseIdx == wPhaseIdx) + { + return H2O::liquidThermalConductivity(temperature, pressure); + } + else + { + return MyCompressibleComponent::liquidThermalConductivity(temperature, pressure); + } + DUNE_THROW(Dune::InvalidStateException, "Invalid phase index " << phaseIdx); + } + +private: + +}; +} // end namespace FluidSystems +} // end namespace Dumux + +#endif diff --git a/tutorial/ex3/spatialparams.hh b/tutorial/ex3/spatialparams.hh new file mode 100644 index 0000000000..1519574eec --- /dev/null +++ b/tutorial/ex3/spatialparams.hh @@ -0,0 +1,196 @@ +// -*- 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 spatial parameters for the fully coupled tutorial problem + * which uses the twophase box model. + */ +#ifndef DUMUX_EXERCISE_THREE_SPATIAL_PARAMS_HH +#define DUMUX_EXERCISE_THREE_SPATIAL_PARAMS_HH + +// include parent spatialparameters +#include + +// include material laws +#include +#include +#include + +namespace Dumux { +//forward declaration +template +class ExerciseThreeSpatialParams; + +namespace Properties +{ +// The spatial parameters TypeTag +NEW_TYPE_TAG(ExerciseThreeSpatialParams); + +// Set the spatial parameters +SET_TYPE_PROP(ExerciseThreeSpatialParams, SpatialParams, + ExerciseThreeSpatialParams); + +// Set the material law +SET_PROP(ExerciseThreeSpatialParams, MaterialLaw) +{ +private: + // material law typedefs + typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; + // select material law to be used + typedef RegularizedBrooksCorey RawMaterialLaw; +public: + // adapter for absolute law + typedef EffToAbsLaw type; +}; +} + +/*! + * \ingroup TwoPBoxModel + * + * \brief The spatial parameters for the fully coupled tutorial problem + * which uses the twophase box model. + */ +template +class ExerciseThreeSpatialParams: public ImplicitSpatialParams +{ + // Get informations for current implementation via property system + typedef typename GET_PROP_TYPE(TypeTag, Grid) Grid; + typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; + typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; + enum + { + dim = Grid::dimension, + dimWorld = Grid::dimensionworld + }; + + // Get object types for function arguments + typedef typename GET_PROP_TYPE(TypeTag, FVElementGeometry) FVElementGeometry; + typedef typename Grid::Traits::template Codim<0>::Entity Element; + +public: + // get material law from property system + typedef typename GET_PROP_TYPE(TypeTag, MaterialLaw) MaterialLaw; + // determine appropriate parameters depending on selected materialLaw + typedef typename MaterialLaw::Params MaterialLawParams; + + /*! Intrinsic permeability tensor K \f$[m^2]\f$ depending + * on the position in the domain + * + * \param element The finite volume element + * \param fvGeometry The finite-volume geometry in the box scheme + * \param scvIdx The local vertex index + * + * Alternatively, the function intrinsicPermeabilityAtPos(const GlobalPosition& globalPos) + * could be defined, where globalPos is the vector including the global coordinates + * of the finite volume. + */ + const Dune::FieldMatrix &intrinsicPermeability(const Element &element, + const FVElementGeometry &fvGeometry, + const int scvIdx) const + { + if (isInLens_(element.geometry().center())) + return KLens_; + return K_; + } + + /*! Defines the porosity \f$[-]\f$ of the porous medium depending + * on the position in the domain + * + * \param element The finite volume element + * \param fvGeometry The finite-volume geometry in the box scheme + * \param scvIdx The local vertex index + * + * Alternatively, the function porosityAtPos(const GlobalPosition& globalPos) + * could be defined, where globalPos is the vector including the global coordinates + * of the finite volume. + */ + Scalar porosity(const Element &element, + const FVElementGeometry &fvGeometry, + const int scvIdx) const + { + if (isInLens_(element.geometry().center())) + return 0.1; + return 0.2; + } + + /*! Returns the parameter object for the material law (i.e. Brooks-Corey) + * depending on the position in the domain + * + * \param element The finite volume element + * \param fvGeometry The finite-volume geometry in the box scheme + * \param scvIdx The local vertex index + * + * Alternatively, the function materialLawParamsAtPos(const GlobalPosition& globalPos) + * could be defined, where globalPos is the vector including the global coordinates + * of the finite volume. + */ + const MaterialLawParams& materialLawParams(const Element &element, + const FVElementGeometry &fvGeometry, + const int scvIdx) const + { + if (isInLens_(element.geometry().center())) + return materialParamsLens_; + return materialParams_; + } + + // constructor + ExerciseThreeSpatialParams(const GridView& gridView) : + ImplicitSpatialParams(gridView), + K_(0), + KLens_(0) + { + //set main diagonal entries of the permeability tensor to a value + //setting to one value means: isotropic, homogeneous + for (int i = 0; i < dim; i++) + { + K_[i][i] = 1e-7; + KLens_[i][i] = 1e-10; + } + + //set residual saturations + materialParams_.setSwr(0.0); + materialParamsLens_.setSwr(0.1); + materialParams_.setSnr(0.0); + materialParamsLens_.setSnr(0.1); + + //parameters of Brooks & Corey Law + materialParams_.setPe(500.0); + materialParamsLens_.setPe(1000.0); + materialParams_.setLambda(2); + materialParamsLens_.setLambda(2); + } + +private: + bool isInLens_(const Dune::FieldVector& globalPos) const + { + const auto x = globalPos[0]; + const auto y = globalPos[1]; + return (x < 40 && x > 20 && y > 35 && y < 45) || + (x < 50 && x > 30 && y < 30 && y > 15); + } + + Dune::FieldMatrix K_; + Dune::FieldMatrix KLens_; + // Object that holds the values/parameters of the selected material law. + MaterialLawParams materialParams_; + MaterialLawParams materialParamsLens_; +}; +} // end namespace +#endif -- GitLab From 47f178c649eb6bbbf2aa0fdf8a239dc4c368b9d8 Mon Sep 17 00:00:00 2001 From: DennisGlaeser Date: Thu, 21 Sep 2017 17:31:48 +0200 Subject: [PATCH 15/42] [tutorial][ex3] add README and solution, finalize exercise --- tutorial/CMakeLists.txt | 1 + tutorial/ex3/README.md | 226 +++++++++ .../ex3/components/mycompressiblecomponent.hh | 110 +---- .../components/myincompressiblecomponent.hh | 110 +---- tutorial/ex3/ex3_a_problem.hh | 36 +- tutorial/ex3/ex3_b_problem.hh | 25 +- .../h2omycompressiblecomponent.hh | 7 +- tutorial/ex3/spatialparams.hh | 11 +- tutorial/extradoc/exercise3_a_solution.png | Bin 0 -> 142019 bytes tutorial/extradoc/exercise3_a_solution2.png | Bin 0 -> 60853 bytes tutorial/extradoc/exercise3_setup.png | Bin 0 -> 45832 bytes .../ex3/h2omycompressiblecomponent.hh | 455 ++++++++++++++++++ .../solution/ex3/mycompressiblecomponent.hh | 108 +++++ .../solution/ex3/myincompressiblecomponent.hh | 82 ++++ 14 files changed, 934 insertions(+), 237 deletions(-) create mode 100644 tutorial/ex3/README.md create mode 100644 tutorial/extradoc/exercise3_a_solution.png create mode 100644 tutorial/extradoc/exercise3_a_solution2.png create mode 100644 tutorial/extradoc/exercise3_setup.png create mode 100644 tutorial/solution/ex3/h2omycompressiblecomponent.hh create mode 100644 tutorial/solution/ex3/mycompressiblecomponent.hh create mode 100644 tutorial/solution/ex3/myincompressiblecomponent.hh diff --git a/tutorial/CMakeLists.txt b/tutorial/CMakeLists.txt index 7e89b59193..546d7e25c8 100644 --- a/tutorial/CMakeLists.txt +++ b/tutorial/CMakeLists.txt @@ -1,3 +1,4 @@ add_subdirectory(ex1) +add_subdirectory(ex3) add_subdirectory(tutorial_implicit) add_subdirectory(tutorial_sequential) diff --git a/tutorial/ex3/README.md b/tutorial/ex3/README.md new file mode 100644 index 0000000000..efacae670e --- /dev/null +++ b/tutorial/ex3/README.md @@ -0,0 +1,226 @@ +# Exercise #3 (DuMuX course) + +The aim of this exercise is to get familiar with the _DuMuX_ way of implementing new components (fluids) and fluid systems (mixtures). In the scope of this exercise, a new fictitious component is implemented (exercise _3a_) as well as its mixture with water (exercise _3b_). + +## Problem set-up + +The domain has a size of 60 x 60 m and contains two low-permeable lenses. Initially, the domain is fully water saturated and the fictitious component is injected through the middle portion of the upper boundary by means of a Neumann boundary condition. The remaining parts of the upper and the entire lower boundary are Neumann no-flow while on the two lateral sides Dirichlet boundary conditions are applied (hydrostatic conditions for the pressure and zero saturation). + + + +## Preparing the exercise + +* Navigate to the directory `dumux/tutorial/ex3` + +### 1. Getting familiar with the code + +Locate all the files you will need for this exercise +* The __main file__ for part a: `ex3_a.cc` +* The __input file__ for part a: `ex3_a.input` +* The __problem file__ for part a: `ex3_a_problem.hh` +* The __main file__ for part b: `ex3_b.cc` +* The __input file__ for part b: `ex3_b.input` +* The __problem file__ for part b: `ex3_b_problem.hh` +* The __spatial parameters file__: `spatialparams.hh` + +Furthermore you will find the following folders: +* `binarycoefficients`: Stores headers containing data/methods on binary mixtures +* `components`: Stores headers containing data/methods on pure components +* `fluidsystems`: Stores headers containing data/methods on mixtures of pure components. Uses methods from `binarycoefficients`. + +To see more components, fluidsystems and binarycoefficients implementations, have a look at the folder `dumux/material`. + +### 2. Implement a new component + +In the following the basic steps required to set the desired fluid system are outlined. Here, this is done in the __problem file__, i.e. for this part of the exercise the code shown below is taken from the `ex3_a_problem.hh` file. + +In this part of the exercise we will consider a system consisting of two immiscible phases. Therefore, the _TypeTag_ for this problem derives from the _BoxTwoP_ _TypeTag_ (for a cell-centered scheme, you would derive from _CCTwoP_). In order to be able to derive from this _TypeTag_, The declaration of the _BoxTwoP_ _TypeTag_ is found in the file `dumux/porousmediumflow/2p/implicit/model.hh`, which has been included in line 28: + +```c++ +// The numerical model +#include +``` + + Additionally we derive from the _ExerciseThreeSpatialParams_ _TypeTag_ in order to set all the types related to the spatial parameters also for our new _TypeTag_ _ExerciseThreeProblem_. In this case, only one property is set for _ExerciseThreeSpatialParams_ (see lines 43 to 60 in `spatialparams.hh`). Alternatively, we could have defined this also here in the problem without defining a new type tag for the spatial parameters. However, in case you want to define several properties related to the spatial parameters it is good practice to define a separate _TypeTag_ and derive from this, as it is done here. + +```c++ +NEW_TYPE_TAG(ExerciseThreeProblem, INHERITS_FROM(BoxTwoP, ExerciseThreeSpatialParams)); +``` + +As wetting phase we want to use water and we want to precompute tables on which the properties are then interpolated in order to save computational time. Thus, in a first step we have to include the following headers: + +```c++ +// The water component +#include +#include +``` +The non-wetting phase will be our new component, where we want to implement an incompressible and a compressible variant. The respective headers are prepared, but still incomplete. The compressible variant is still commented so that compilation does not fail when finishing the incompressible variant. + +```c++ +// The components that will be created in this exercise +#include "components/myincompressiblecomponent.hh" +// #include "components/mycompressiblecomponent.hh" +``` +As mentioned above, we want to simulate two non-mixing components. The respective fluid system is found in: + +```c++ +// The two-phase immiscible fluid system +#include +``` + +This fluid system expects __phases__ as input and so far we have only included the components, which contain data on the pure component for all physical states. Thus, we need to include + +```c++ +// We will only have liquid phases Here +#include +``` + +which creates a _liquid phase_ from a given component. Finally, using all of the included classes we set the the fluid system property by choosing a liquid phase consisting of the incompressible fictitious component as non-wetting phase and tabulated water as the wetting phase in the immiscible fluid system: + + +```c++ +// we use the immiscible fluid system here +SET_PROP(ExerciseThreeProblem, FluidSystem) +{ +private: + typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; + typedef TabulatedComponent> TabulatedH2O; + typedef typename FluidSystems::LiquidPhase WettingPhase; + /*! + * Uncomment first line and comment second line for using the incompressible component + * Uncomment second line and comment first line for using the compressible component + */ + typedef typename FluidSystems::LiquidPhase > NonWettingPhase; + // typedef typename FluidSystems::LiquidPhase > NonWettingPhase; + +public: + typedef typename FluidSystems::TwoPImmiscible type; +}; +``` + +### 2.1. incompressible component + +Open the file `myincompressiblecomponent.hh`. You can see in line 40 that a component should always derive from the _Component_ class (see `dumux/material/components/component.hh`), which defines the interface of a _DuMuX_ component with all possibly required functions to be overloaded by the actual implementation. + +```c++ +/*! + * \ingroup Components + * \brief A ficitious component to be implemented in exercise 3. + * + * \tparam Scalar The type used for scalar values + */ +template +class MyIncompressibleComponent : public Component > +``` + +__Task__: + +Implement an incompressible component into the file `myincompressiblecomponent.hh`, which has the following specifications: + +| Parameter | unit | value | +| -----| --------| -------- | +| $`M`$ | $`Kg/mol`$ | $`131.39 \cdot 10^{-3}`$ | +| $`\rho_{liquid}`$ | $`Kg/m^3`$ | $`1460`$ | +| $`\mu_{liquid}`$ | $`Pa \cdot s`$ | $`5.7 \cdot 10^{-4}`$ | + +In order to do so, have a look at the file `dumux/material/components/component.hh` to see how the interfaces are defined and overload them accordingly. + +Execute the program by changing to the build-directory + +```bash +cd build-cmake/tutorial/ex3 +``` + +and by compiling the executable for part a + +```bash +make ex3_a +``` + +and by typing + +```bash +./ex3_a ex3_a.input +``` + +The saturation distribution at the final simulation time should look like this: + + + +### 2.1. incompressible component + +We now want to implement a pressure-dependent density for our component. Open the file `mycompressiblecomponent.hh` and copy in the functions you implemented for the incompressible variant. Now substitute the method that returns the density by the following expression: + +$` \rho_{min} + (\rho_{max} - \rho_{min})/(1 + \rho_{min}*exp(-1.0*k*(\rho_{max} - \rho_{min})*p)) `$, + +where $`p`$ is the pressure and $`\rho_{min} = 1440 `$, $`\rho_{max} = 1480 `$ and $`k = 5 \cdot 10^{-7} `$. Also, make sure the header is included in the `ex3_a_problem.hh` file by uncommenting line 42. Furthermore, the new component has to be set as the non-wetting phase in the fluid system, i.e. comment line 81 and uncomment line 82. The non-wetting density distribution at the final simulation time should look like this: + + + +### 3. Implement a new fluid system + +The problem file for this part of the exercise is `ex3_b_problem.hh`. We now want to implement a new fluid system consisting of two liquid phases, which are water and the previously implemented compressible component. We will consider compositional effects, which is why we now have to derive our _TypeTag_ from the _BoxTwoPTwoC_ _TypeTag_: + +```c++ +// The numerical model +#include +``` + +```c++ +// Create a new type tag for the problem +NEW_TYPE_TAG(ExerciseThreeProblem, INHERITS_FROM(BoxTwoPTwoC, ExerciseThreeSpatialParams)); +``` + +The new fluid system is to be implemented in the file `fluidsystems/h2omycompressiblecomponent.hh`. This is already included in the problem and the fluid system property is set accordingly. + +```c++ +// The fluid system that is created in this exercise +#include "fluidsystems/h2omycompressiblecomponent.hh" +``` + +```c++ +// The fluid system property +SET_PROP(ExerciseThreeProblem, FluidSystem) +{ +private: + typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; +public: + typedef FluidSystems::H2OMyCompressibleComponent type; +}; +``` + +In the `fluidsystems/h2omycompressiblecomponent.hh` file, your implemented component and the binary coefficient files are already included. + +```c++ +// the ficitious component that was created in exercise 3a +#include + +// the binary coefficients corresponding to this fluid system +#include +``` + +__Task__: + +Under the assumption that one molecule of _MyCompressibleComponent_ displaces exactly one molecule of water, the water phase density can be expressed as follows: + +$` \rho_{w} = \frac{ \rho_{w, pure} }{ M_{H_2O} }*(M_{H_2O}*x_{H_2O} + M_{MyComponent}*x_{MyComponent}) `$ + +Implement this dependency in the _density()_ method in the fluid system. Then, execute the program by changing to the build-directory + +```bash +cd build-cmake/tutorial/ex3 +``` + +and by compiling the executable for part b + +```bash +make ex3_b +``` + +and by typing + +```bash +./ex3_b ex3_b.input +``` + +You will observe an error message and an abortion of the program. This is due to the fact that in order for the constraint solver and other mechanisms in the two-phase two-component model to work, two additional functionalities in the component have to be implemented. The model has to know whether or not the liquid pure component is compressible and it needs the vapour pressure. As in the previous exercise, check the `dumux/material/components/component.hh` file for these two functions and implement them into `mycompressiblecomponent.hh`. For the vapour pressure, use a value of $`3900`$ Pa. diff --git a/tutorial/ex3/components/mycompressiblecomponent.hh b/tutorial/ex3/components/mycompressiblecomponent.hh index 44db2b6326..65d48fe25a 100644 --- a/tutorial/ex3/components/mycompressiblecomponent.hh +++ b/tutorial/ex3/components/mycompressiblecomponent.hh @@ -48,115 +48,9 @@ public: { return "MyCompressibleComponent"; } /*! - * \brief The molar mass in \f$\mathrm{[kg/mol]}\f$ of MyCompressibleComponent. + * TODO: Copy the methods implemented in MyIncompressibleComponent and substitute + * the density calculation by the expression given in the exercise description. */ - static Scalar molarMass() - { - return 131.39e-3; // [kg/mol] - } - - /*! - * \brief Returns the critical temperature \f$\mathrm{[K]}\f$ of MyCompressibleComponent. - */ - static Scalar criticalTemperature() - { - DUNE_THROW(Dune::NotImplemented, "criticalTemperature for MyCompressibleComponent"); - } - - /*! - * \brief Returns the critical pressure \f$\mathrm{[Pa]}\f$ of MyCompressibleComponent. - */ - static Scalar criticalPressure() - { - DUNE_THROW(Dune::NotImplemented, "criticalPressure for MyCompressibleComponent"); - } - - /*! - * \brief Returns the temperature \f$\mathrm{[K]}\f$ at MyCompressibleComponent's triple point. - */ - static Scalar tripleTemperature() - { - DUNE_THROW(Dune::NotImplemented, "tripleTemperature for MyCompressibleComponent"); - } - - /*! - * \brief Returns the pressure \f$\mathrm{[Pa]}\f$ at MyCompressibleComponent's triple point. - */ - static Scalar triplePressure() - { - DUNE_THROW(Dune::NotImplemented, "triplePressure for MyCompressibleComponent"); - } - - /*! - * \brief The vapor pressure in \f$\mathrm{[Pa]}\f$ of pure MyCompressibleComponent - * at a given temperature. - * - * \param T temperature of component in \f$\mathrm{[K]}\f$ - */ - static Scalar vaporPressure(Scalar T) - { - return 3900; // [Pa] (at 20C) - } - - /*! - * \brief Returns true if the gas phase is assumed to be compressible - */ - static bool gasIsCompressible() - { return true; } - - /*! - * \brief Returns true if the liquid phase is assumed to be compressible - */ - static bool liquidIsCompressible() - { return true; } - - /*! - * \brief The density of steam at a given pressure and temperature \f$\mathrm{[kg/m^3]}\f$. - * - * \param temperature temperature of component in \f$\mathrm{[K]}\f$ - * \param pressure pressure of component in \f$\mathrm{[Pa]}\f$ - */ - static Scalar gasDensity(Scalar temperature, Scalar pressure) - { - return IdealGas::density(molarMass(), - temperature, - pressure); - } - - /*! - * \brief Returns true if the gas phase is assumed to be ideal - */ - static bool gasIsIdeal() - { return true; } - - /*! - * TODO: implement the given pressure-dependent relationship for the liquid density - * - * \brief The density of pure TCE at a given pressure and temperature \f$\mathrm{[kg/m^3]}\f$. - * - * \param temperature temperature of component in \f$\mathrm{[K]}\f$ - * \param pressure pressure of component in \f$\mathrm{[Pa]}\f$ - */ - static Scalar liquidDensity(Scalar temperature, Scalar pressure) - { - static const Scalar rho_min = 1440; - static const Scalar rho_max = 1480; - static const Scalar k = 5e-7; - - using std::exp; - return rho_min + (rho_max - rho_min)/(1 + rho_min*exp(-1.0*k*(rho_max - rho_min)*pressure)); // [kg/m^3] - } - - /*! - * \brief The dynamic viscosity \f$\mathrm{[Pa*s]}\f$ of pure TCE. - * - * \param temperature temperature of component in \f$\mathrm{[K]}\f$ - * \param pressure pressure of component in \f$\mathrm{[Pa]}\f$ - */ - static Scalar liquidViscosity(Scalar temperature, Scalar pressure) - { - return 5.7e-4;// [Pa*s] - } }; } // end namespace diff --git a/tutorial/ex3/components/myincompressiblecomponent.hh b/tutorial/ex3/components/myincompressiblecomponent.hh index 33adf654b1..9809100b21 100644 --- a/tutorial/ex3/components/myincompressiblecomponent.hh +++ b/tutorial/ex3/components/myincompressiblecomponent.hh @@ -39,11 +39,6 @@ namespace Dumux template class MyIncompressibleComponent : public Component > { - - /*! - * TODO: Implement the missing specifications from the given data sheet. - */ - public: /*! * \brief A human readable name for MyIncompressibleComponent. @@ -52,111 +47,8 @@ public: { return "MyIncompressibleComponent"; } /*! - * TODO - * \brief The molar mass in \f$\mathrm{[kg/mol]}\f$ of MyIncompressibleComponent. - */ - static Scalar molarMass() - { - return 131.39e-3; // [kg/mol] - } - - /*! - * \brief Returns the critical temperature \f$\mathrm{[K]}\f$ of MyIncompressibleComponent. - */ - static Scalar criticalTemperature() - { - DUNE_THROW(Dune::NotImplemented, "criticalTemperature for MyIncompressibleComponent"); - } - - /*! - * \brief Returns the critical pressure \f$\mathrm{[Pa]}\f$ of MyIncompressibleComponent. - */ - static Scalar criticalPressure() - { - DUNE_THROW(Dune::NotImplemented, "criticalPressure for MyIncompressibleComponent"); - } - - /*! - * \brief Returns the temperature \f$\mathrm{[K]}\f$ at MyIncompressibleComponent's triple point. - */ - static Scalar tripleTemperature() - { - DUNE_THROW(Dune::NotImplemented, "tripleTemperature for MyIncompressibleComponent"); - } - - /*! - * \brief Returns the pressure \f$\mathrm{[Pa]}\f$ at MyIncompressibleComponent's triple point. - */ - static Scalar triplePressure() - { - DUNE_THROW(Dune::NotImplemented, "triplePressure for MyIncompressibleComponent"); - } - - /*! - * \brief The vapor pressure in \f$\mathrm{[Pa]}\f$ of pure MyIncompressibleComponent - * at a given temperature. - * - * \param T temperature of component in \f$\mathrm{[K]}\f$ - */ - static Scalar vaporPressure(Scalar T) - { - return 3900; // [Pa] (at 20C) - } - - /*! - * \brief Returns true if the gas phase is assumed to be compressible - */ - static bool gasIsCompressible() - { return true; } - - /*! - * \brief Returns true if the liquid phase is assumed to be compressible - */ - static bool liquidIsCompressible() - { return false; } - - /*! - * \brief The density of steam at a given pressure and temperature \f$\mathrm{[kg/m^3]}\f$. - * - * \param temperature temperature of component in \f$\mathrm{[K]}\f$ - * \param pressure pressure of component in \f$\mathrm{[Pa]}\f$ - */ - static Scalar gasDensity(Scalar temperature, Scalar pressure) - { - return IdealGas::density(molarMass(), - temperature, - pressure); - } - - /*! - * \brief Returns true if the gas phase is assumed to be ideal - */ - static bool gasIsIdeal() - { return true; } - - /*! - * TODO - * \brief The density of pure TCE at a given pressure and temperature \f$\mathrm{[kg/m^3]}\f$. - * - * \param temperature temperature of component in \f$\mathrm{[K]}\f$ - * \param pressure pressure of component in \f$\mathrm{[Pa]}\f$ - */ - static Scalar liquidDensity(Scalar temperature, Scalar pressure) - { - return 1460.0; // [kg/m^3] - } - - /*! - * TODO - * \brief The dynamic viscosity \f$\mathrm{[Pa*s]}\f$ of pure TCE. - * - * \param temperature temperature of component in \f$\mathrm{[K]}\f$ - * \param pressure pressure of component in \f$\mathrm{[Pa]}\f$ + * TODO: Implement the methods for the component data given in the exercise description. */ - static Scalar liquidViscosity(Scalar temperature, Scalar pressure) - { - return 5.7e-4;// [Pa*s] - } }; } // end namespace diff --git a/tutorial/ex3/ex3_a_problem.hh b/tutorial/ex3/ex3_a_problem.hh index b4a9ebe147..897d5c57ca 100644 --- a/tutorial/ex3/ex3_a_problem.hh +++ b/tutorial/ex3/ex3_a_problem.hh @@ -39,12 +39,12 @@ // The components that will be created in this exercise #include "components/myincompressiblecomponent.hh" -#include "components/mycompressiblecomponent.hh" +// #include "components/mycompressiblecomponent.hh" // We will only have liquid phases Here #include -// The fluid system that is used +// The two-phase immiscible fluid system #include namespace Dumux{ @@ -74,14 +74,12 @@ private: typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; typedef TabulatedComponent> TabulatedH2O; typedef typename FluidSystems::LiquidPhase WettingPhase; - /*! - * TODO: define the liquid phase of your component as the non-wetting phase - * Solution: Uncomment first line and comment second line for exercise 3a - * Uncomment second line and comment first line for exercise 3b + * Uncomment first line and comment second line for using the incompressible component + * Uncomment second line and comment first line for using the compressible component */ - // typedef typename FluidSystems::LiquidPhase > NonWettingPhase; - typedef typename FluidSystems::LiquidPhase > NonWettingPhase; + typedef typename FluidSystems::LiquidPhase > NonWettingPhase; + // typedef typename FluidSystems::LiquidPhase > NonWettingPhase; public: typedef typename FluidSystems::TwoPImmiscible type; @@ -244,6 +242,28 @@ public: values[Indices::contiNEqIdx]= 0.0; } + /*! + * \brief Append all quantities of interest which can be derived + * from the solution of the current time step to the VTK + * writer. Adjust this in case of anisotropic permeabilities. + */ + void addOutputVtkFields() + { + // get the number of elements in the grid + unsigned numElements = this->gridView().size(/*codim=*/0); + + // create the scalar field required for the output of the lenses + typedef Dune::BlockVector > ScalarField; + ScalarField *isInLens = this->resultWriter().allocateManagedBuffer(numElements); + + // add data to the scalar field + for (const auto& element : elements(this->gridView())) + (*isInLens)[this->model().elementMapper().index(element)] = this->spatialParams().isInLens(element.geometry().center()); + + // attach to writer + this->resultWriter().attachCellData(*isInLens, "isInLens"); + } + private: // small epsilon value Scalar eps_; diff --git a/tutorial/ex3/ex3_b_problem.hh b/tutorial/ex3/ex3_b_problem.hh index a6ef025781..766396f329 100644 --- a/tutorial/ex3/ex3_b_problem.hh +++ b/tutorial/ex3/ex3_b_problem.hh @@ -62,9 +62,6 @@ SET_PROP(ExerciseThreeProblem, FluidSystem) private: typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; public: - /*! - * TODO: set the fluid system created in this exercise as the property - */ typedef FluidSystems::H2OMyCompressibleComponent type; }; @@ -225,6 +222,28 @@ public: int initialPhasePresenceAtPos(const GlobalPosition &globalPos) const { return Indices::wPhaseOnly; } + /*! + * \brief Append all quantities of interest which can be derived + * from the solution of the current time step to the VTK + * writer. Adjust this in case of anisotropic permeabilities. + */ + void addOutputVtkFields() + { + // get the number of elements in the grid + unsigned numElements = this->gridView().size(/*codim=*/0); + + // create the scalar field required for the output of the lenses + typedef Dune::BlockVector > ScalarField; + ScalarField *isInLens = this->resultWriter().allocateManagedBuffer(numElements); + + // add data to the scalar field + for (const auto& element : elements(this->gridView())) + (*isInLens)[this->model().elementMapper().index(element)] = this->spatialParams().isInLens(element.geometry().center()); + + // attach to writer + this->resultWriter().attachCellData(*isInLens, "isInLens"); + } + private: // small epsilon value Scalar eps_; diff --git a/tutorial/ex3/fluidsystems/h2omycompressiblecomponent.hh b/tutorial/ex3/fluidsystems/h2omycompressiblecomponent.hh index d29d3758f8..b02bce3398 100644 --- a/tutorial/ex3/fluidsystems/h2omycompressiblecomponent.hh +++ b/tutorial/ex3/fluidsystems/h2omycompressiblecomponent.hh @@ -219,14 +219,13 @@ public: // http://elib.uni-stuttgart.de/bitstream/11682/271/1/Diss_Ochs_OPUS.pdf Scalar rholH2O = H2O::liquidDensity(fluidState.temperature(phaseIdx), fluidState.pressure(phaseIdx)); Scalar clH2O = rholH2O/H2O::molarMass(); + Scalar x_H2O = fluidState.moleFraction(wPhaseIdx, H2OIdx); + Scalar x_myComp = fluidState.moleFraction(wPhaseIdx, NAPLIdx); /*! * TODO: implement the composition-dependent water density from the exercise sheet. */ - return - clH2O*(H2O::molarMass()*fluidState.moleFraction(wPhaseIdx, H2OIdx) - + - MyCompressibleComponent::molarMass()*fluidState.moleFraction(wPhaseIdx, NAPLIdx)); + return ???; } else { // assume the density of the fictious component to be independent of the composition diff --git a/tutorial/ex3/spatialparams.hh b/tutorial/ex3/spatialparams.hh index 1519574eec..4d5f0635f9 100644 --- a/tutorial/ex3/spatialparams.hh +++ b/tutorial/ex3/spatialparams.hh @@ -105,7 +105,7 @@ public: const FVElementGeometry &fvGeometry, const int scvIdx) const { - if (isInLens_(element.geometry().center())) + if (isInLens(element.geometry().center())) return KLens_; return K_; } @@ -125,7 +125,7 @@ public: const FVElementGeometry &fvGeometry, const int scvIdx) const { - if (isInLens_(element.geometry().center())) + if (isInLens(element.geometry().center())) return 0.1; return 0.2; } @@ -145,7 +145,7 @@ public: const FVElementGeometry &fvGeometry, const int scvIdx) const { - if (isInLens_(element.geometry().center())) + if (isInLens(element.geometry().center())) return materialParamsLens_; return materialParams_; } @@ -177,8 +177,7 @@ public: materialParamsLens_.setLambda(2); } -private: - bool isInLens_(const Dune::FieldVector& globalPos) const + bool isInLens(const Dune::FieldVector& globalPos) const { const auto x = globalPos[0]; const auto y = globalPos[1]; @@ -186,6 +185,8 @@ private: (x < 50 && x > 30 && y < 30 && y > 15); } +private: + Dune::FieldMatrix K_; Dune::FieldMatrix KLens_; // Object that holds the values/parameters of the selected material law. diff --git a/tutorial/extradoc/exercise3_a_solution.png b/tutorial/extradoc/exercise3_a_solution.png new file mode 100644 index 0000000000000000000000000000000000000000..fdf3ef23c81a0bc414554a9bc2e4f1e784e134c4 GIT binary patch literal 142019 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 z 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�H71hrClG-}9va$l5IyX0+O8OY+ z=-9pDIjTWzM`Lo^`vJV*I=_AUHalx+V`Jm&T&$A`<6tWkRa;vNT`cf;Je*E8@l96N z9W)``)dttsyI>)p7mt|0k8&=LfS>AE@dHRD0nX0?_lRDnWPgf5{r``k;rM@ZT*kO$ WT#8}~zLf14Ul}R+-!dd_KmI=~+vHaO literal 0 HcmV?d00001 diff --git a/tutorial/extradoc/exercise3_a_solution2.png b/tutorial/extradoc/exercise3_a_solution2.png new file mode 100644 index 0000000000000000000000000000000000000000..ba90e6fcfa783fcc5a4eaf1c5fbe252dc46ea8d9 GIT binary patch literal 60853 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±b858VCyDlC~Jm!@=~WSaMjkMt-z+2tvVj4?o_v;@AC;Ek=({ zL+cU0z@ZZbzBw9}Gs-FV8FRqdVtG_gEtibw_ms8*UYClAHDrYpP43}&)+eYkjGNAg5WJsf33nNo>k6cp439HkiOZ%Zrk+ZP8TM4Y7a z3RPUDhS_lb8~~&t}S~RI|W@k z)V_WpwFxY}l&?5FxFn2zQ4?1&{=>%1%xUtRT*4XwDC4DfJ0H43f&3CKP@nT;>>jnT z1q(3X$;5PgE|x)h9bS1)34U9dM>;kFu6u{+F_EFlcl~x&e@|7<f{I84g6a)}P-NJ}pvo z7Lt^6-zKT8W9Ov>hN&$dv{!$~vEsHauC6vuYUybKC>1w&(kjsQ;Ai6E#~E3!oEH@p zMWspnbcI6D!3aSlwNEj~goV+yix%T@Rv3`;+vQ6hb$aH`#KaIByH@gKOfNt^To1~A zmwX*Ik8_G|K?Wz?TIEH%oW3r~)zHvT5a+mX!t0F|Fwx`KM1mowj>g7DQwqwFH9ABZ zlL6v@UNB7_e0_Vcu@L=oe%lWQH?GO}gIoV#sL;RV4?D#}M+x7CnW_ zAQcG*_AA99B8196UjF_iK-8!u3T?pq3prB45rT)(oJpCGHx@n)3XXy*tMq;`0m^S~ z4RVQ{iKerH2A*qh_7{=Nywo8$F`^d2N*ODJ12y*Fc3~!<{qDR>BPB29Q{6{xc^uP+p+^gKk9)g%1m<=AgZoO@|5e16}%>#MA+-Z3V&wl8FY0Abfa zU3&+I7|DRHwAgCO%GHL`%O&)U*ko1&+}WeZN1qC>BN0!1o@%JBJ#|Xx@B8)d3VuiO zMI0g3^#ZER9S}?wFy$(uddYAJ5|KIArSMliT5t>tYXhuQ#Vp-SOPIDcPJNU%>3*c=Q A?f?J) literal 0 HcmV?d00001 diff --git a/tutorial/extradoc/exercise3_setup.png b/tutorial/extradoc/exercise3_setup.png new file mode 100644 index 0000000000000000000000000000000000000000..eed8371e6a96f9b4d4eee22849f4b3bbbcd83fa1 GIT binary patch literal 45832 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 literal 0 HcmV?d00001 diff --git a/tutorial/solution/ex3/h2omycompressiblecomponent.hh b/tutorial/solution/ex3/h2omycompressiblecomponent.hh new file mode 100644 index 0000000000..47822a8647 --- /dev/null +++ b/tutorial/solution/ex3/h2omycompressiblecomponent.hh @@ -0,0 +1,455 @@ +// -*- 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 A fluid system with water and a ficitious component, which is to be + * implemented in tutorial exercise 3a, as phases and components. This + * fluid system is to be implemented in exercise 3b. + */ +#ifndef DUMUX_H2O_MYCOMPRESSIBLECOMPONENT_FLUID_SYSTEM_HH +#define DUMUX_H2O_MYCOMPRESSIBLECOMPONENT_FLUID_SYSTEM_HH + +#include +#include + +#include + +// the ficitious component that was created in exercise 3a +#include + +// the binary coefficients corresponding to this fluid system +#include + +namespace Dumux +{ +namespace FluidSystems +{ + +/*! + * \brief A compositional fluid consisting of two liquid phases, + * which are water and a ficitious component from tutorial exercise 3a. + */ +template > > +class H2OMyCompressibleComponent + : public BaseFluidSystem< Scalar, H2OMyCompressibleComponent > +{ + typedef H2OMyCompressibleComponent ThisType; + typedef BaseFluidSystem Base; + +public: + typedef Dumux::MyCompressibleComponent MyCompressibleComponent; + typedef H2OType H2O; + + static const int numPhases = 2; + static const int numComponents = 2; + + static const int wPhaseIdx = 0; // index of the water phase + static const int nPhaseIdx = 1; // index of the NAPL phase + + static const int H2OIdx = 0; + static const int NAPLIdx = 1; + + // export component indices to indicate the main component + // of the corresponding phase at atmospheric pressure 1 bar + // and room temperature 20°C: + static const int wCompIdx = H2OIdx; + static const int nCompIdx = NAPLIdx; + + /*! + * \brief Initialize the fluid system's static parameters generically + * + * If a tabulated H2O component is used, we do our best to create + * tables that always work. + */ + static void init() + { + init(/*tempMin=*/273.15, + /*tempMax=*/623.15, + /*numTemp=*/100, + /*pMin=*/0.0, + /*pMax=*/20e6, + /*numP=*/200); + } + + /*! + * \brief Initialize the fluid system's static parameters using + * problem specific temperature and pressure ranges + * + * \param tempMin The minimum temperature used for tabulation of water [K] + * \param tempMax The maximum temperature used for tabulation of water [K] + * \param nTemp The number of ticks on the temperature axis of the table of water + * \param pressMin The minimum pressure used for tabulation of water [Pa] + * \param pressMax The maximum pressure used for tabulation of water [Pa] + * \param nPress The number of ticks on the pressure axis of the table of water + */ + static void init(Scalar tempMin, Scalar tempMax, unsigned nTemp, + Scalar pressMin, Scalar pressMax, unsigned nPress) + { + if (H2O::isTabulated) { + std::cout << "Initializing tables for the H2O fluid properties (" + << nTemp*nPress + << " entries).\n"; + + H2O::init(tempMin, tempMax, nTemp, + pressMin, pressMax, nPress); + } + } + + + /*! + * \brief Return whether a phase is liquid + * + * \param phaseIdx The index of the fluid phase to consider + */ + static bool isLiquid(int phaseIdx) + { + assert(0 <= phaseIdx && phaseIdx < numPhases); + return true; + } + + static bool isIdealGas(int phaseIdx) + { return H2O::gasIsIdeal() && MyCompressibleComponent::gasIsIdeal(); } + + /*! + * \brief Returns true if and only if a fluid phase is assumed to + * be an ideal mixture. + * + * We define an ideal mixture as a fluid phase where the fugacity + * coefficients of all components times the pressure of the phase + * are indepent on the fluid composition. This assumtion is true + * if Henry's law and Raoult's law apply. If you are unsure what + * this function should return, it is safe to return false. The + * only damage done will be (slightly) increased computation times + * in some cases. + * + * \param phaseIdx The index of the fluid phase to consider + */ + static bool isIdealMixture(int phaseIdx) + { + assert(0 <= phaseIdx && phaseIdx < numPhases); + return true; + } + + /*! + * \brief Returns true if and only if a fluid phase is assumed to + * be compressible. + * + * Compressible means that the partial derivative of the density + * to the fluid pressure is always larger than zero. + * + * \param phaseIdx The index of the fluid phase to consider + */ + static bool isCompressible(int phaseIdx) + { + assert(0 <= phaseIdx && phaseIdx < numPhases); + if (phaseIdx == wPhaseIdx) + // the water component decides for the water phase... + return H2O::liquidIsCompressible(); + + // the NAPL component decides for the napl phase... + return MyCompressibleComponent::liquidIsCompressible(); + } + + /*! + * \brief Return the human readable name of a phase (used in indices) + */ + static std::string phaseName(int phaseIdx) + { + switch (phaseIdx) { + case wPhaseIdx: return "w"; + case nPhaseIdx: return "n"; + }; + DUNE_THROW(Dune::InvalidStateException, "Invalid phase index " << phaseIdx); + } + + /*! + * \brief Return the human readable name of a component (used in indices) + */ + static std::string componentName(int compIdx) + { + switch (compIdx) { + case H2OIdx: return H2O::name(); + case NAPLIdx: return MyCompressibleComponent::name(); + }; + DUNE_THROW(Dune::InvalidStateException, "Invalid component index " << compIdx); + } + + /*! + * \brief Return the molar mass of a component in [kg/mol]. + */ + static Scalar molarMass(int compIdx) + { + switch (compIdx) { + case H2OIdx: return H2O::molarMass(); + case NAPLIdx: return MyCompressibleComponent::molarMass(); + }; + DUNE_THROW(Dune::InvalidStateException, "Invalid component index " << compIdx); + } + + /*! + * \brief Given all mole fractions in a phase, return the phase + * density [kg/m^3]. + */ + using Base::density; + template + static Scalar density(const FluidState &fluidState, int phaseIdx) + { + assert(0 <= phaseIdx && phaseIdx < numPhases); + if (phaseIdx == wPhaseIdx) { + // See: doctoral thesis of Steffen Ochs 2007 + // Steam injection into saturated porous media : process analysis including experimental and numerical investigations + // http://elib.uni-stuttgart.de/bitstream/11682/271/1/Diss_Ochs_OPUS.pdf + Scalar rholH2O = H2O::liquidDensity(fluidState.temperature(phaseIdx), fluidState.pressure(phaseIdx)); + Scalar clH2O = rholH2O/H2O::molarMass(); + Scalar x_H2O = fluidState.moleFraction(wPhaseIdx, H2OIdx); + Scalar x_myComp = fluidState.moleFraction(wPhaseIdx, NAPLIdx); + + // return composition-dependent water phase density + return clH2O*(H2O::molarMass()*x_H2O + MyCompressibleComponent::molarMass()*x_myComp); + } + else { + // assume the density of the fictious component to be independent of the composition + Scalar pressure = MyCompressibleComponent::liquidIsCompressible()?fluidState.pressure(phaseIdx):1e100; + return MyCompressibleComponent::liquidDensity(fluidState.temperature(phaseIdx), pressure); + } + } + + /*! + * \brief Return the viscosity of a phase. + */ + using Base::viscosity; + template + static Scalar viscosity(const FluidState &fluidState, + int phaseIdx) + { + assert(0 <= phaseIdx && phaseIdx < numPhases); + if (phaseIdx == wPhaseIdx) { + // assume pure water viscosity + return H2O::liquidViscosity(fluidState.temperature(phaseIdx), + fluidState.pressure(phaseIdx)); + } + else { + // assume pure NAPL viscosity + return MyCompressibleComponent::liquidViscosity(fluidState.temperature(phaseIdx), fluidState.pressure(phaseIdx)); + } + } + + using Base::diffusionCoefficient; + template + static Scalar diffusionCoefficient(const FluidState &fluidState, int phaseIdx, int compIdx) + { + DUNE_THROW(Dune::NotImplemented, "Diffusion coefficients"); + } + + /*! + * \brief Given a phase's composition, temperature and pressure, + * return the binary diffusion coefficient \f$\mathrm{[m^2/s]}\f$ for components + * \f$\mathrm{i}\f$ and \f$\mathrm{j}\f$ in this phase. + * \param fluidState The fluid state + * \param paramCache mutable parameters + * \param phaseIdx Index of the fluid phase + * \param compIIdx Index of the component i + * \param compJIdx Index of the component j + */ + using Base::binaryDiffusionCoefficient; + template + static Scalar binaryDiffusionCoefficient(const FluidState &fluidState, + int phaseIdx, + int compIIdx, + int compJIdx) + { + assert(0 <= phaseIdx && phaseIdx < numPhases); + assert(0 <= compIdx && compIdx < numComponents); + + const Scalar T = fluidState.temperature(phaseIdx); + const Scalar p = fluidState.pressure(phaseIdx); + + // we assume the diffusion coefficient to be the same in both phases + return Dumux::BinaryCoeff::H2O_MyCompressibleComponent::liquidDiffCoeff(T, p); + } + + /* Henry coefficients + */ + template + static Scalar henryCoefficient(const FluidState &fluidState, + int phaseIdx, + int compIdx) + { + assert(0 <= phaseIdx && phaseIdx < numPhases); + assert(0 <= compIdx && compIdx < numComponents); + + const Scalar T = fluidState.temperature(phaseIdx); + const Scalar p = fluidState.pressure(phaseIdx); + + if (compIdx == NAPLIdx && phaseIdx == wPhaseIdx) + return Dumux::BinaryCoeff::H2O_MyCompressibleComponent::henryMyCompressibleComponentInWater(T)/p; + + else if (phaseIdx == nPhaseIdx && compIdx == H2OIdx) + return Dumux::BinaryCoeff::H2O_MyCompressibleComponent::henryWaterInMyCompressibleComponent(T)/p; + + else + DUNE_THROW(Dune::InvalidStateException, "non-existent henry coefficient for phase index " << phaseIdx + << " and component index " << compIdx); + } + + using Base::fugacityCoefficient; + /*! + * \brief Returns the fugacity coefficient \f$\mathrm{[-]}\f$ of a component in a + * phase. + * + * In this case, things are actually pretty simple. We have an ideal + * solution. Thus, the fugacity coefficient is 1 in the gas phase + * (fugacity equals the partial pressure of the component in the gas phase + * respectively in the liquid phases it is the inverse of the + * Henry coefficients scaled by pressure + * \param fluidState The fluid state + * \param phaseIdx The index of the phase + * \param compIdx The index of the component + */ + template + static Scalar fugacityCoefficient(const FluidState &fluidState, + int phaseIdx, + int compIdx) + { + assert(0 <= phaseIdx && phaseIdx < numPhases); + assert(0 <= compIdx && compIdx < numComponents); + + Scalar T = fluidState.temperature(phaseIdx); + Scalar p = fluidState.pressure(phaseIdx); + + if (phaseIdx == wPhaseIdx) { + if (compIdx == H2OIdx) + return H2O::vaporPressure(T)/p; + else if (compIdx == NAPLIdx) + return Dumux::BinaryCoeff::H2O_MyCompressibleComponent::henryMyCompressibleComponentInWater(T)/p; + } + + // for the NAPL phase, we assume currently that nothing is + // dissolved. this means that the affinity of the NAPL + // component to the NAPL phase is much higher than for the + // other components, i.e. the fugacity coefficient is much + // smaller. + Scalar phiNapl = MyCompressibleComponent::vaporPressure(T)/p; + if (compIdx == NAPLIdx) + return phiNapl; + else + return 1e6*phiNapl; + } + + template + static Scalar kelvinVaporPressure(const FluidState &fluidState, + const int phaseIdx, + const int compIdx) + { + DUNE_THROW(Dune::NotImplemented, "FluidSystems::H2OMyCompressibleComponent::kelvinVaporPressure()"); + } + + /* partial pressures in the gas phase, taken from saturation vapor pressures + */ + template + static Scalar partialPressureGas(const FluidState &fluidState, int phaseIdx, + int compIdx) + { + assert(0 <= compIdx && compIdx < numComponents); + + const Scalar T = fluidState.temperature(phaseIdx); + if (compIdx == NAPLIdx) + return MyCompressibleComponent::vaporPressure(T); + else if (compIdx == H2OIdx) + return H2O::vaporPressure(T); + else + DUNE_THROW(Dune::InvalidStateException, "non-existent component index " << compIdx); + } + + /* inverse vapor pressures, taken from inverse saturation vapor pressures + */ + template + static Scalar inverseVaporPressureCurve(const FluidState &fluidState, + int phaseIdx, + int compIdx) + { + assert(0 <= compIdx && compIdx < numComponents); + + const Scalar pressure = fluidState.pressure(phaseIdx); + if (compIdx == NAPLIdx) + return MyCompressibleComponent::vaporTemperature(pressure); + else if (compIdx == H2OIdx) + return H2O::vaporTemperature(pressure); + else + DUNE_THROW(Dune::InvalidStateException, "non-existent component index " << compIdx); + } + + + + /*! + * \brief Given all mole fractions in a phase, return the specific + * phase enthalpy [J/kg]. + */ + using Base::enthalpy; + template + static Scalar enthalpy(const FluidState &fluidState, + int phaseIdx) + { + assert(0 <= phaseIdx && phaseIdx < numPhases); + if (phaseIdx == wPhaseIdx) { + return H2O::liquidEnthalpy(fluidState.temperature(phaseIdx), fluidState.pressure(phaseIdx)); + } + else { + return MyCompressibleComponent::liquidEnthalpy(fluidState.temperature(phaseIdx), fluidState.pressure(phaseIdx)); + } + DUNE_THROW(Dune::InvalidStateException, "Invalid phase index " << phaseIdx); + } + + using Base::heatCapacity; + template + static Scalar heatCapacity(const FluidState &fluidState, + int phaseIdx) + { + DUNE_THROW(Dune::NotImplemented, "FluidSystems::H2ONAPL::heatCapacity()"); + } + + using Base::thermalConductivity; + template + static Scalar thermalConductivity(const FluidState &fluidState, + int phaseIdx) + { + assert(0 <= phaseIdx && phaseIdx < numPhases); + + const Scalar temperature = fluidState.temperature(phaseIdx) ; + const Scalar pressure = fluidState.pressure(phaseIdx); + if (phaseIdx == wPhaseIdx) + { + return H2O::liquidThermalConductivity(temperature, pressure); + } + else + { + return MyCompressibleComponent::liquidThermalConductivity(temperature, pressure); + } + DUNE_THROW(Dune::InvalidStateException, "Invalid phase index " << phaseIdx); + } + +private: + +}; +} // end namespace FluidSystems +} // end namespace Dumux + +#endif diff --git a/tutorial/solution/ex3/mycompressiblecomponent.hh b/tutorial/solution/ex3/mycompressiblecomponent.hh new file mode 100644 index 0000000000..6f349b541d --- /dev/null +++ b/tutorial/solution/ex3/mycompressiblecomponent.hh @@ -0,0 +1,108 @@ +// -*- 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 + * \ingroup Components + * \brief A ficitious component to be implemented in exercise 3. + */ +#ifndef DUMUX_MYCOMPRESSIBLECOMPONENT_HH +#define DUMUX_MYCOMPRESSIBLECOMPONENT_HH + +#include +#include + + +namespace Dumux +{ +/*! + * \ingroup Components + * \brief A ficitious component to be implemented in exercise 3. + * + * \tparam Scalar The type used for scalar values + */ +template +class MyCompressibleComponent : public Component > +{ +public: + /*! + * \brief A human readable name for MyCompressibleComponent. + */ + static std::string name() + { return "MyCompressibleComponent"; } + + /*! + * \brief The molar mass in \f$\mathrm{[kg/mol]}\f$ of MyCompressibleComponent. + */ + static Scalar molarMass() + { + return 131.39e-3; // [kg/mol] + } + + /*! + * \brief The density of MyCompressibleComponent at a given pressure and temperature \f$\mathrm{[kg/m^3]}\f$. + * + * \param temperature temperature of component in \f$\mathrm{[K]}\f$ + * \param pressure pressure of component in \f$\mathrm{[Pa]}\f$ + */ + static Scalar liquidDensity(Scalar temperature, Scalar pressure) + { + static const Scalar rho_min = 1440; + static const Scalar rho_max = 1480; + static const Scalar k = 5e-7; + + using std::exp; + return rho_min + (rho_max - rho_min)/(1 + rho_min*exp(-1.0*k*(rho_max - rho_min)*pressure)); // [kg/m^3] + } + + /*! + * \brief The dynamic viscosity \f$\mathrm{[Pa*s]}\f$ of MyCompressibleComponent. + * + * \param temperature temperature of component in \f$\mathrm{[K]}\f$ + * \param pressure pressure of component in \f$\mathrm{[Pa]}\f$ + */ + static Scalar liquidViscosity(Scalar temperature, Scalar pressure) + { + return 5.7e-4;// [Pa*s] + } + + /***************************************************************** + * The function below is implemented in the scope of exercise 3b * + *****************************************************************/ + + /*! + * \brief The vapor pressure in \f$\mathrm{[Pa]}\f$ of MyCompressibleComponent + * at a given temperature. + * + * \param T temperature of component in \f$\mathrm{[K]}\f$ + */ + static Scalar vaporPressure(Scalar T) + { + return 3900; // [Pa] (at 20C) + } + + /*! + * \brief Returns true if the liquid phase is assumed to be compressible + */ + static bool liquidIsCompressible() + { return false; } +}; + +} // end namespace + +#endif diff --git a/tutorial/solution/ex3/myincompressiblecomponent.hh b/tutorial/solution/ex3/myincompressiblecomponent.hh new file mode 100644 index 0000000000..f8af80ea8a --- /dev/null +++ b/tutorial/solution/ex3/myincompressiblecomponent.hh @@ -0,0 +1,82 @@ +// -*- 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 + * \ingroup Components + * \brief A ficitious component to be implemented in tutorial exercise 3. + */ +#ifndef DUMUX_MYINCOMPRESSIBLECOMPONENT_HH +#define DUMUX_MYINCOMPRESSIBLECOMPONENT_HH + +#include +#include + + +namespace Dumux +{ +/*! + * \ingroup Components + * \brief A ficitious component to be implemented in exercise 3. + * + * \tparam Scalar The type used for scalar values + */ +template +class MyIncompressibleComponent : public Component > +{ +public: + /*! + * \brief A human readable name for MyIncompressibleComponent. + */ + static std::string name() + { return "MyIncompressibleComponent"; } + + /*! + * \brief The molar mass in \f$\mathrm{[kg/mol]}\f$ of MyIncompressibleComponent. + */ + static Scalar molarMass() + { + return 131.39e-3; // [kg/mol] + } + + /*! + * \brief The density of MyIncompressibleComponent at a given pressure and temperature \f$\mathrm{[kg/m^3]}\f$. + * + * \param temperature temperature of component in \f$\mathrm{[K]}\f$ + * \param pressure pressure of component in \f$\mathrm{[Pa]}\f$ + */ + static Scalar liquidDensity(Scalar temperature, Scalar pressure) + { + return 1460.0; // [kg/m^3] + } + + /*! + * \brief The dynamic viscosity \f$\mathrm{[Pa*s]}\f$ of MyIncompressibleComponent. + * + * \param temperature temperature of component in \f$\mathrm{[K]}\f$ + * \param pressure pressure of component in \f$\mathrm{[Pa]}\f$ + */ + static Scalar liquidViscosity(Scalar temperature, Scalar pressure) + { + return 5.7e-4;// [Pa*s] + } +}; + +} // end namespace + +#endif -- GitLab From a3d650d41e39321d0babdee3e456e1e06935d785 Mon Sep 17 00:00:00 2001 From: DennisGlaeser Date: Thu, 21 Sep 2017 18:23:26 +0200 Subject: [PATCH 16/42] [tutorial][ex3] fix embedding of images --- tutorial/ex3/README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tutorial/ex3/README.md b/tutorial/ex3/README.md index efacae670e..87c7781ccb 100644 --- a/tutorial/ex3/README.md +++ b/tutorial/ex3/README.md @@ -6,7 +6,8 @@ The aim of this exercise is to get familiar with the _DuMuX_ way of implementing The domain has a size of 60 x 60 m and contains two low-permeable lenses. Initially, the domain is fully water saturated and the fictitious component is injected through the middle portion of the upper boundary by means of a Neumann boundary condition. The remaining parts of the upper and the entire lower boundary are Neumann no-flow while on the two lateral sides Dirichlet boundary conditions are applied (hydrostatic conditions for the pressure and zero saturation). - +![](../extradoc/exercise3_setup.png) + ## Preparing the exercise @@ -145,7 +146,7 @@ and by typing The saturation distribution at the final simulation time should look like this: - +![](../extradoc/exercise3_a_solution.png) ### 2.1. incompressible component @@ -155,7 +156,7 @@ $` \rho_{min} + (\rho_{max} - \rho_{min})/(1 + \rho_{min}*exp(-1.0*k*(\rho_{max} where $`p`$ is the pressure and $`\rho_{min} = 1440 `$, $`\rho_{max} = 1480 `$ and $`k = 5 \cdot 10^{-7} `$. Also, make sure the header is included in the `ex3_a_problem.hh` file by uncommenting line 42. Furthermore, the new component has to be set as the non-wetting phase in the fluid system, i.e. comment line 81 and uncomment line 82. The non-wetting density distribution at the final simulation time should look like this: - +![](../extradoc/exercise3_a_solution2.png) ### 3. Implement a new fluid system -- GitLab From 723e80f1a99ea5332f2aa30d761c76a2ec5893dd Mon Sep 17 00:00:00 2001 From: DennisGlaeser Date: Thu, 21 Sep 2017 18:25:11 +0200 Subject: [PATCH 17/42] [tutorial][ex3] fix errors in README --- tutorial/ex3/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tutorial/ex3/README.md b/tutorial/ex3/README.md index 87c7781ccb..e803a7e838 100644 --- a/tutorial/ex3/README.md +++ b/tutorial/ex3/README.md @@ -99,7 +99,7 @@ public: }; ``` -### 2.1. incompressible component +### 2.1. Incompressible component Open the file `myincompressiblecomponent.hh`. You can see in line 40 that a component should always derive from the _Component_ class (see `dumux/material/components/component.hh`), which defines the interface of a _DuMuX_ component with all possibly required functions to be overloaded by the actual implementation. @@ -148,11 +148,11 @@ The saturation distribution at the final simulation time should look like this: ![](../extradoc/exercise3_a_solution.png) -### 2.1. incompressible component +### 2.2. Compressible component We now want to implement a pressure-dependent density for our component. Open the file `mycompressiblecomponent.hh` and copy in the functions you implemented for the incompressible variant. Now substitute the method that returns the density by the following expression: -$` \rho_{min} + (\rho_{max} - \rho_{min})/(1 + \rho_{min}*exp(-1.0*k*(\rho_{max} - \rho_{min})*p)) `$, +$`\rho_{MyComp} = \rho_{min} + \frac{ \rho_{max} - \rho_{min} }{ 1 + \rho_{min}*e^{-1.0*k*(\rho_{max} - \rho_{min})*p} } `$, where $`p`$ is the pressure and $`\rho_{min} = 1440 `$, $`\rho_{max} = 1480 `$ and $`k = 5 \cdot 10^{-7} `$. Also, make sure the header is included in the `ex3_a_problem.hh` file by uncommenting line 42. Furthermore, the new component has to be set as the non-wetting phase in the fluid system, i.e. comment line 81 and uncomment line 82. The non-wetting density distribution at the final simulation time should look like this: -- GitLab From 93682d33d4f352a04fa8006defe1cd52bcd84136 Mon Sep 17 00:00:00 2001 From: DennisGlaeser Date: Fri, 22 Sep 2017 11:53:31 +0200 Subject: [PATCH 18/42] [tutorial][ex3] change CMakeLists.txt --- tutorial/ex3/CMakeLists.txt | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/tutorial/ex3/CMakeLists.txt b/tutorial/ex3/CMakeLists.txt index aa345e72bf..447a9a5f87 100644 --- a/tutorial/ex3/CMakeLists.txt +++ b/tutorial/ex3/CMakeLists.txt @@ -1,11 +1,17 @@ -add_input_file_links() +# executables for exercise part a & b +dune_add_test(NAME ex3_a + SOURCES ex3_a.cc) +dune_add_test(NAME ex3_b + SOURCES ex3_b.cc) -add_dumux_test(ex3_a ex3_a ex3_a.cc ${CMAKE_CURRENT_BINARY_DIR}/exercise3) -add_dumux_test(ex3_b ex3_b ex3_b.cc ${CMAKE_CURRENT_BINARY_DIR}/exercise3) +# add a symlink for the input file +dune_symlink_to_source_files(FILES "ex3_a.input" "ex3_b.input") #install sources install(FILES -exercise3.cc -exercise3_problem.hh -exercise3_spatialparams.hh -DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/dumux/tutorial/material_exercise) +ex3_a.cc +ex3_a_problem.hh +ex3_b.cc +ex3_b_problem.hh +spatialparams.hh +DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/dumux/tutorial/ex3) -- GitLab From 27a84ae4c93306462caec09d048d64bb026243ca Mon Sep 17 00:00:00 2001 From: Timo Koch Date: Thu, 21 Sep 2017 10:46:30 +0200 Subject: [PATCH 19/42] Update ex2 readme --- tutorial/ex2/README.md | 29 +++++++++++++++++++-- tutorial/extradoc/exercise2_properties.png | Bin 0 -> 12676 bytes 2 files changed, 27 insertions(+), 2 deletions(-) create mode 100644 tutorial/extradoc/exercise2_properties.png diff --git a/tutorial/ex2/README.md b/tutorial/ex2/README.md index 49de2542c7..df76d44fc1 100644 --- a/tutorial/ex2/README.md +++ b/tutorial/ex2/README.md @@ -54,7 +54,7 @@ DuMuX uses the term _material law_ to describe the law used to compute The file `mymateriallaw.hh` contains a custom implementation of such a material law. -* Implement the method `Scalar pc(Scalar sw)` by implementing your own capillary pressure relationship, e.g. pc(Sw) = 1e5*(1-Sw). +* Implement the method `Scalar pc(Scalar sw)` by implementing your own capillary pressure relationship, e.g. a simple linear relationship $`p_C(S_w) = 1\cdot 10^5 \cdot (1-S_w)`$. The type (i.e. C++ type) of the material law is set in the file `injection2pspatialparams.hh` by using the DuMuX property system @@ -74,7 +74,7 @@ Verify your changes by recompiling and running the program. You should see a plo Most types in DuMuX are properties that can be changed just like the material law. In the following task we implement our own 2p2c local residual, i.e. the class that computes the element residual in every Newton step. The file `mylocalresidual.hh` contains a copy of the original local residual class used for the 2p2c model renamed to `template class MyTwoPTwoCLocalResidual`. -* Make DuMuX use this new local residual by setting the corresponding property in the `Property` namespace in the file `injection2p2cproblem.hh` +* Make DuMuX use this new local residual by inluding the header `mylocalresidual.hh` and setting the corresponding property in the `Property` namespace in the file `injection2p2cproblem.hh` ```c++ // note that every property struct knows about TypeTag @@ -116,7 +116,23 @@ namespace Properties ... ``` +* Then enhance the problem TypeTag (the master TypeTag) by inheriting from the created node (in `injection2p2cproblem.hh`) + +```c++ +... + NEW_TYPE_TAG(Injection2p2cProblem, // the problem TypeTag + INHERITS_FROM(TwoPTwoC, // the 2p2c model TypeTag node + InjectionSpatialParams, // the spatial params TypeTag node + MyLocalResidualParams)); // the local residual params TypeTag node +... +``` +Note: the property inheritance graph now looks like this + +![property tree](../extradoc/exercise2_properties.png) + + * Modify the `computeFlux` method to only call the `diffusiveFlux` method if diffusion is enabled. You can get the new parameter by adding the lines + ```c++ // ... in the constructor of MyTwoPTwoCLocalResidual enableDiffusion_ = GET_PARAM_FROM_GROUP(TypeTag, bool, @@ -126,3 +142,12 @@ namespace Properties private: bool enableDiffusion_; ``` + +You can now enable and disable diffusion through the input file + +```ini +[Problem] +EnableDiffusion = true / false +``` + +Verify the difference at the non-wetting saturation front with and without diffusion. diff --git a/tutorial/extradoc/exercise2_properties.png b/tutorial/extradoc/exercise2_properties.png new file mode 100644 index 0000000000000000000000000000000000000000..741443216f00bf5209b62b9a486dbf930976f8d2 GIT binary patch literal 12676 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 bDxlj(=fg=ys1NXq2^>XvHM!FFX2Jgh<@fFq literal 0 HcmV?d00001 -- GitLab From 383762e31c21a270b00b46870795e9e60d070e8f Mon Sep 17 00:00:00 2001 From: Timo Koch Date: Thu, 21 Sep 2017 10:53:31 +0200 Subject: [PATCH 20/42] Improve ex2 image --- tutorial/extradoc/exercise2_properties.png | Bin 12676 -> 27453 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/tutorial/extradoc/exercise2_properties.png b/tutorial/extradoc/exercise2_properties.png index 741443216f00bf5209b62b9a486dbf930976f8d2..28c700ed18443d78995d890cb7fb085a84146ff7 100644 GIT binary patch literal 27453 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 A#sB~S literal 12676 zcmeI3^;gq>^v6*UL_ zvl8$J&*imG%rWijv}t*gAgs}|JS)x+G`3dh64 zgWJv#;sQ2@S#d+1ZBq6mf!#jCQIvb9?U}lZ_V7#@ySP2Xc(HgXRZ^hB1yV)hi5}J} z29?V`*KkjkF?=OquawH$*sMzMv^)5I?o->Tm(@G(jm|*fyE|{sK%Po-!!G^--A?Wn z619|ZL)(qsKmUtKcTui|run^<`~U6#@4)}%9XKOl13e(N;sU$Zne1{jLM)Uve)iNnMs01HbNImqfNKcNA%2CZdv#>N}skc<}-odhUiF zlQuIYE)-oR{n6C>cJb%oH(9x9)7eYgVyzY;NqTy6a?@}~g1f%&60( zT1HC9fcUGmPNId&%Q*wnQ98$QMMT z=97U|O<%@HtScbNHYEaOuS+bYDL%+Aoj6Xb)Ex?F6`5en7(xyDcyaxL-uz+oT@SUHTZ7HwqRs_gHGp3C(d$>l4%&I#Pbd zyW|J(kRN)DNZx>Oqxqx7DEt4JDg1R;J%1f?(O$C`HVy{OZwDxxz4ZBEdnGbNW5M7; z*p*65WS^Y`?=;hE6fN^K#`JtEycm(F+)0C*rB!Pjl4irggS3K9NZ$CB@FCxiN`l0M zFhwM9>I{OHzxkUjDiO(a#ZA5IO!V3p(m*I$ zyes?Zrx+F1Y_h~JxKLr#)paq=F(sWUTy(+^QYsWW$7pgx(tpn-pg{VRaF1D^y6)9r z${OJrt!EH~7W$0G(J2tZwIA5PDanet7VWB-|Ky*Qe9%0>tb`agbHsI?=E{<)y0 z-N?sOfhCo@j{D&#La5H5kND3e`I#_;XjY5%+f8mZmiy{~{5ow1b0DsG<*fBN9vDij z+IuTG7qp`e|7kny$icMR=>EDQ8r_s$Qw)o2YI1hIaoN=lCVcwTG?*{oe#)4%Rdpeh z$lZQ*<*IHP@oRxg9@pt2;tRzzqFBl-2=&|>Vte#;e~GdG#w;;B?>Nd74_L44_rcc@DSj?`}q2J?PAi ztl+s%>+nPm`KD466M4`SR*jbH;T!P_3S1{!h!aNGpqzqCKeMf)DfZuaQ>P8?NTA7$YqJfqYqABuiyA!)rv_4#N$?`yGjorLOA1Esyo-(0rPYP>9va;F z;7vszl&jezTJ5N=X%W6=3L<34Mq^4w*f;*Vix7+?yc@Il%EEkq3*PBm2 z!ifxeZlGwyTD+r1n8PMcv>&VT;Zs$9c8)|Ba*yW~(^%Y)xdg=;+i0F3(stobnhC%6 zf8Ui!`xf-rI~yw-@sYFc@2Nx>;(P9)&q4NTMEJWm!h}e(8FN7bVi$Edc+L4eK!>#J-iHDj@eq zbs0(WIwn8nkrntE6EIA2(|^im2UjN_nQkj{1JAQct}Vpc9Og_ zr8c-Irk_P>3RnNez_=?{o$KYuey(0)Op1crsz?6WGj=eBk{6W};NIxq9WlcZ85=|O<-AXUKFL{)hg>qn=zX$3j~Fds z4(tAdGvv=+8204I+^$uVuW(xy0B#v7-y(+c?25ej|tV%V4+CjY&aEoZE3 z@@L7Z*71xTOY~S|{17+@#hmfT2@>2|vtVbh?p3?Vbs%(;Lzk5x7t=-qqbn;Zb}Eec zqs#0m6{=%J{D!kIyEM~)lN?{}MLLz+=S%3De!M+M59CHFKiI`t!pU=9`$i(*SlUKC zz@+`_9EUMq zo2g4y{jnzJJzobs8D-<3F03bOnkHTj{W#p+`_%{yzwr;ui%2`JOXpaV*zv@V90DicE8HCMl1fd(7Xo6%q^AtbJbs-rN6}gt=PhkyDBpI7uHTwkRgEFtOZa0IhPp({ zn0%Bk5bo`f4bEW^{h_0f+*BL7ntRGHH8hm;5>bwEXiUOoP*6h(tyf6bkM6vssj3`mUZ^ z$sxpQ5Uzh3FpStf6c25VQcWtTxw^{W6q98CIVwk*@#c{ha}C4oI<#l^XaBchZ(Th> z4dib)EoadMH$!G^+tKvSBjBOOGaGkzHy3{1HnA=)z+XV363R>Y-vd{`hw<;LjJq87 zrDIxl<~)c;o6s;w)K%p!9!;j!p|O@uG>?l(gA#QXy?z>>&K@zME%HB*5+3#aGjJt7KgXmx`yWozy>Jw`$ue;f zFE`1$=VIv6QsJ>yo~rHd`8KfNvBwpZkyFV?XJi4WbVS`MOFd<^%ht(2TtbHoOF@h&p-)AQF*3L^6usFUwSC6G$><_5@ST1 z_p&1zHV9~qMJ?(W{c&hIDkQwNx~HavUl>jMyig+`behGnkFX+ihpGla`*D~?Cn z6h+{koph+>u4i-4L3+=u^ZPm}LN~}bLlYJvie#-zy@+^Td^-XgM~kKY3=sVqL5gmM zUT?4J6u+JqCnMd0%dO@Zhhk>ENB2^0>ATcF2(|?HFBwRAoeej05jKR^F#P*X-Rq8| zx!m2$Du5X1epGk&E-nMEs-1e7z@@7rVw39N=)6!1Ed`(dYVbnRPmzR> zNmlnS>O4{JaJ6zP594?+k3^h1)djn|eG+u125Gb*b^$?n?#9UouR8exuj%e>mRG%k6(0 zuy$|U>oR&uSFG5zW)}EM3L>MJ6+{;UaX>MPpDo*jtJrLL#!4ep7Nxkv@!@toIvz$pERA66RAn@Mp?1CUERoRpRxR5bawK%pr)N6 z$zIKdwFE%8Nd1tp1Vj4+^~;FEQN3IiPoj${4tpX6{n<&q5roTqsbFbfJy&H_rwcHH z`m>@c)`1mLyCpaH-|3PY(Y7q{iOMlqsYhW!_?<)wbX4pIX~`;%F+txZRppC(r{O7~ zY33>lKRR6ERX9`5RbQ6_5@IJI0p14P!BNY_b2TRN90kMs9eYWAIts3fb@?X?KU&`0 zHyfU6Dkund9+KEjZqD*9!unV9%BeQ>kzVG&+V8!)+XpGZ15xX@fdN#BeD2zM&4!=> zD|Mb_X6n_0NSy{S;Yp?D}ac zGAk*>o5cm>&rY%v+uv8!dng(zQbzyQ!0m@QI=yWUJUYdS~Be^cPNxuY(YZ^pW#yAPx^@;-b3q!?6z) zRK;I@d>%NaE%me(3sW<0WxlO)NBE2@Z~+N=A^)W~g%j7^&NrUFi{8rU%94H3{gB2^F?Gvrw$UbU>PEVT1-dt<#iy;&5XN7RSGHcZjaCFfr}$TfSI5?1uJ_3 zKKzwVO?L${xuG%C0P=}umMgsA@%l=h7VmFPCX~j6nZdMvAE$AH7?}jyxFvFb)}H@* zF3+0vPl90o<*J4>=VV8TX)${BKt<}Gt{-R)M&$c?mKy}lxS z6VMQAnAKmYjhBFyLb}z=9vzK)-FATyM=2uX2P3G&k2-b7(_2Tw;%vwUDpcSQL=+ZL zqx}+_=RDsq1t_tIyl*uY^-Au4?zxNgmJ5^(6)tr9`;Y4gYt&c5HB5eVVDpZ~kxHNp zlXpX|%pR$8A)GNA?OGBW-LuJhHhM6BfA%?pCrj5**;GN6?%-3m;!@j%FYWwyy3aIY zHf@>Ufv3AS2T%Vi@V_qcx%xbr5$=5yhwMmFL!&q5L8qX09x?h~0%6Ieif{u=jy=6O zhv!BvtaE;h%!!MhK1D|16e9q%Ep2G>G3BfvBrvHxHRQ#g<0r{T%)VI!gT3SAX7Pb!Fqv zO1NLBvY0jpV}5gKI37kPdR-P_phpXNf#k~%1|${HesVttDVN1f z<0SQ9IO&^}q@a8JAEjnbmXyYIg{v+slX~!~(0VyF{eq$91Bjk8wiZOti6u|WRSs#c z4jIr27-*Tw%8oiu&`MpPs9CRy>Qkc@AJ(NM$vc)=&Ve+-C%~RAjt>;hFfNCgX~|W2 z37ec2$DcrHCW9G618b*Zl*L8%W`0(m)f2UAg!^~(`%2k&&@$!GPV)1^y(Y(0js?s8 zA;Zbd7PLiu+hSJwbYbf`&hrHHG%l9Z+){5sfEYonC(1Y#V?cpDdn7n3Rdsprx8T~AZ^+vSkmvGmjrk(mG$sV)w-;H@$|mbUWg z0(5W_pX8JMw@dB39D*EB1SR^elaHzhaM)g&L)bmJi&FJl2sV1Q)~rO#-@|7M|Is(* z&Ph(V&k$%+`n_94^z^7)m`Y3HPb*?TLd$HVDJklFo{BP+maU3AVE2Z@Bb&r8^iAg8 z{;46_g8%8#`1}Je?A!FK%;{IS{1oB!32<*^ztP-c@!r41EWMDdda8CeP4XrZCIaEl zhI4%Okqs5jANOu9>i%^hyW~u9_F2j$m}Jpm4fX1~8&2{181*fReTVI#6%4e*%FlK` zh39^S7VCRXYX54)HUsI1aiTRlTxT_99;%b3tYhN09AG4^PcywW?X_K7>SQn0cad^h zv945SO9}nWy0^u&XmYZ-^MPflo~P!lvr-5bKpj^slM%~|Dg@Y9f?`mcW81THfeVzp z*wsNGP7N{l@%Y%sgW=zK92lRMkPA0}%QGUHV8L$pGnc-UW9`T!_<@Rq^PBz+GuI;_ zp#Y3{LZYnJ(O|R(4fYX1>vq%?oh_p4W^PERtHDi=+OsLv)JVC?=V#rjx+|a#AAOLi z{~oE$QzxueygknvyQ5Zd@t@i&6Zo9v}zXu4emDh^q(hGJ6$ zh25BtD;^0$5UFXr+i}RA0V7@BwtD=VGM!wSb9A9p_mJ9Rfq$W|Aq=OZasMafW&uR1 zCCcLomYnD96#AtuUKiyJS%1b7qed9-S!}N&K|n*1a_=5fMY~Mtfg^7V#DOmyB+J_) zTgfx7D7}el5=BB^6EbxucdkkvS`p4)&GX*XWxc-N8yU&}<;^Ptl%NOT5PhpUzGD8o z01Swo;QXSV_*qf?(D^_2M-!4Qsds$_MhN$np-xAeRJ@q$Qt+CicMTA@RTtq{nx7w$B@ox^s4I2skW`)HgO8t2N zE##D+Vz(RFCizjw?R;k(DKb@&SJtNSY@dk;+9i-g!Y{Dk@fhx6F8Up#@EBTG`-_=a z^-gl|2AFVB%o_}im?j=g7dwyZ3i1Nb=hD{Ray3KVO0~*n9?SNp3-*};pJ1xmc>7FG z?>PUqWO?%5JvBdDGU!0j!k@Nx&f@HGv0GL*jdZ16{_-Q&h8s``L;Xfbmw4&=i(gqn z52zUCqhe4@ZvjnT24Ef*&hYu>hR_b@kAT`v1B4*oUKko^k6JS}{z`EPBd)Hl)Kb08 z=sFtN?-bG;T(5`B?|L=>Bz*gt+h(W0kwJpDm5bdnmh#|mW1Uq3&FxA}#pW63ZZPvR zVa9kq-OL!Z-SE(MtTuX{V7#(@J1V`xy8Y{#P&gaS#0Mlb?tE6>%r5krpFV1Rv477A@ zYvHJYLjL>6`@I`?E|<~Fu~!!R1rb~1CpW0Qt~1}7#MPl{-TISbeG&zMvhY+Ra0fnR8zU|lP8}HdOHR<2f;udsg+pi zzRtqmHDej10zYvn`jd994Ls&KI^LkXG;}VF{M=h!Na6JOcIt@1fkzS0OXGC>7V!^Pd@jNyY^|(h?U{O-;~W zaxu)H25f}Kkg0}eG~eI|B89|^NYY=Egw(e>wk#3V#q^P!VNZfR1t=y{kWczLpdkR4 z`1``dAMli9L0bEMR8}si@RznSRb@_fmN5i>t3n*>$Kyp+Z^{#E1K{UIe&CeU zPN}o1mB9F`XRxVs0xD`UaDDc01{TXW@O6&j#_0=+rvLaYrWOe$NZJ(r=kl5@TA$$# zgd@-_tQs1wc%cC}A>z-{Ypbc2jTzyt2ip#Q%dO{2%-~(qpi&3FefR2z;DGV;u$g@H zN7wZ2BZm1H9ySOc>1SN4x;@2XO?bW+f-fq0?=c=S(R_y)a~4ltoZDq~y8|g`sVafv zOT>AhjRQ=Su00_QjJ9)RKMpmmh~i&guX@z1Gi$?)4;86EQ&|_&fERE+oF?$~0rf0r9>T`&rt&ANs!Vr-c=^?x%+AXA&>B|n7Sb!E2e>-6hg zd5pR=9f?RA-OifPyST{wV6aW9J>yWH>i+yB$GsM8ibi(>RX^8TdPm%P0;1!n)#%>0 zdoB)W*B>Sjv_S`0MwujOL4jPtH-lS6U1YQ3GU zH01;0^<_~FR9IorfX4(R{_=!u(r2RYa-uS(CTjjwwWU5{7!XG7)Z$W~PaA?zaJ_ad zm-YMSsG*%t#aM3GGeI``EcQ^gn2iM~`C`IZ{_R)BK5UZ$n}Ipt%x*p;mD_G#iPT)J zP^~h*gaL7jqS8C3bQDZ_l6j=Jgbm(v-_*RnFa4`uCSbQ%?dm58%BGCViO-+Q^Ddn- z2BE}eYtCRHwD>2}9W#zN5(KGb<$LQin5s0^82!rdX56)3U18SmPd-Ph3#a5Jk1k_y zaGspr%>tnLn_8m86%4`AcrIUS+`sbe+>BnNaT2TZ!FP-o=^i%hDQU3rDXbaBL zDqdt2#;B_jsSZNUBBvK7X>p5DE`sAsxRK8iJPmyqTqt>m46&@y#}z`S%sQ%)uKTkQ zV41N!)$~CTf3ipx7A7-dsp1+mBe=2{63=Trll|y*BwtM{{^O!H6Pv8?d2KaD-RZca zD-kMdINqFtl5prnshz0*{zYdMo5NLc>cf9GOv)Y*RgrR&Vm>f2OP~qv8u4Qxd@XRK z38_6S+uiM{jpo4UtOG`54+bFle8aw$$yCcdLe)WpLyV)ib>k2-3}3wKq$Xi+e0anx zzV1qjFSNkTfwfEfei0+8n04vR@Bbuhli_kcb?2ug)!F)$eET>Z;FzQb|7=&zw|o@r zTQm5#f&jp=0z3@~17=t^3*-BGAWAXMTXHpbd#1?g8F%88Pl zHy&o~3166NNwvj{m{4R_4f zM`a@30zz1g1RihsUv}ydy$zQqjK}=2rKWZ!RJur*h@H^na;x+aDkn^unR z2qc#lPNs_PW}6n(yK@bCdm>oA|L)C{{>0{iC538f41`(L%y*HJ2Kz82F0w*IPi+uU zmc9JlZ^A##7H3?AMw9VjeLj6Z0*5Nz!DRg!2t~%){78rYrc-TIP~*1um%o+%fw%nA zj<1j@O9gBzElzp3UCaMIyPLNwM7aBJ!Ie&u%vfkTU(U3AllZUNoW7ef^>)SJTO={^CHx8uXt>;-qtJ~tJe9n)2lIiI`N7I#TDvI!$O znL^OU@f9#xplb=)H7VU``C(h@cH7#h(R6EEo)T@hY0ZFj^kJhns$0ERzl*?YGu7}F znrtDTiFlP@$+mu-E7kW@GixdqOECWBe)#(RG9l^V0nsz5+w)|CS_P+ZYKPzds@KW! zfD?v9R*+V3^yvFE#YMV)_Hzzv5*9FbeE+M`pDt8@o_T7aF`eRf9tjjZwX&{yjOTN@ z9|6WUgftp#5V|@=ZaP*_|KYBzYV&o>#D^#o4SrglJRNtU`tnhUTEJX8f@E?IC?1~0 zooaSh`8AWe|HeEYey=2mxI4}>?c4h>DxAquB*A>te7fmGtcglhG<|c zp~w~5rwF)=pF1b~sav3?oiAs)}kPo-;P z*k}WBRf4_Dw*_+Lro+ew)Xq_qppcq%!S!j*5AKULVb(hb4b_&Un6#9E!2X0XNzvae z8Hhpq34y&254=f{B~p){++&3^K8gk=h0Nf7`qKsP?g2*g{GtolL}hVK^mORj?hOp^ zAE3q*DaOVC)R(vObLp@xG0l(R+!>ks(tR_4z$%}~jBDLKej`zuwe#K|0KVec>;igv zF8zTx9ycCb`~LJxD1!XsHKfv|wdkym8c$>XMg4vV@ts#_L!!Q(2Np0eqFro@5#~KC zPCwa8ZOxY1><}1Hrv1nMKsprY2^)4lJ9;v7_%Yirj2Wy-y1s+H{*=v-9^bq54WHZR z6YZ(y%y4;pc9JQsUd_pu7X!I;1GT^m(nI56cp@;;@Zn5#HFwF`x}q>ZhE&$ zyk<=*LJ)XB!uP|+vMVh2dZh9I*R;puG>6Up`jBJ`4tR(Dj!a`ehY~_*6Mm}1O_&2; z0@j!_)Af~v((f07a$H5dA|lD&dF%`7u6HybRj7u=o7hhrb?FOWU8^(rQHtDZGsKE6elkT@Q@;c{-PnKZnmyN9>6FdlGr@Uq0GqPx_teNGsd ztokB}ERJ#>sW91G!tmD{kpnB3;hzX4*bEra09Fd@eC2`u!gMw`M6YSs zFOrVtnN@^l!ScRoHz9y|Q)gX|yjkzeMcP8prCWFu8!Y%&l@hG5ejFL;7;{@)a==}1Kk6EA-#5xBDfm#u1(s=p zE7$pMRORY0_{`V2l3vox2_y#$l`Ir5ZeHDtG9e|aQtym`mW!WPOEqIijKf#JtN{j! zmU?)UMJqEh@_Bm9flhf(WxuCWz3V1jVJ&A^Mj-Yp1fbT7eTUamG|>l}aj%6x(*u~7 z?v9V|i%l{3?Tg@C+1frS1B*gD>DHxcEnT|tK@E*E0M-Bk@(9DDbZ+g(#RK{mbK76G z0@xtMuS#sZ45VxrehjVx##qf1rBMsC54DSJ>%CDCf;-4D&fTw-kSGKIfJiB0D`Nh$ z=gu)X4!~oLWgH&d`GPLT!}m5u#DW4$1p*Uo5{`FHJ`N7;%PsbP;tsGD!yv1o@zjfN zuTc$~mJfW5PyX=h{+yt2T8tfPUJj+!gAK$c&mPX#+&zCF8>!Ke({K3$;}H|;Mr||m zpX)s%YIF!(RhIyV8z4u&a>RSTgt@lg2b%d_;8;L+pTp)|f3>*^gwD6Co!w7DR1|*M z12QVHAAbL{&%R8*5&}kQpyd~~l=zlxN7G~17XUhS^l=kPY1Bfh6}wDq)4Z?Y29UI; zl}Z4BeY&9Y#vwI-p8$DY{PoQ~6@OA2jUrzbC8m4Oe$L*K^9 z$}U&l4*(0i?p)U}X=%`!v}2ICf|-9UOVC?9wr5f)wu2Q$=)aF*>~bTEKutN8ABOy0 zA$xpwQbjREJ7(+N+M4!<#1MDkhq>K}it<9vbGxVW(mzoCbo38M*t|TwR08gNJjA>K zD!F51lkUK2{J_}#(*iA-I&Js*y+lB(uqk4qm%owRKt?+w1<(L zml72&@c)j)SuTVFw24bs+hxTC05V9DQjLS6c@4>yK$iXGKx_Olj0414CgN zX^64^v;3Om;M za@a(FOvnK_0+)6Cxlyupo{O2mjQqGxgR4m_hJSo=3VZXnOnB)dLbYsQ z>&RQ$)KI?O(S_JbVd9?lSc9r6+t<@w`yz`J6fl@l-e_@**P^PL%LS2hBU3hEIcxk1 zNg0=XSKL!un960UrBkO9^~rA(TsALl5nBsXN$wmpzreg3Iwp{+MB^&Gpu(AR1Huyubaxw(KbhNu(tE;B0A7q-LH0IeKx zNFsN}{7GCW{&tO4HWKAUNkg-*Z`fz1_o3Lu`t-+amM7{3mU_$<&f&ZN{1`XLwzOt# zsC@TRK~n}F@@q;`5zEWNUv#RRcqqyY%c!((R{tTvcA=~^0@8vUm{m`L7g!!v_&A*a zdL84_CE7J-%{O&OV&h}YSReoXG>D)+zzn@tMr|jfBU%bEy&~YPVZ2IgPVlFr& z9jzo?{0}$qPw@DIa=LC=Lkb@l;pUOdMp2E^fX9s>R2JxqdUufL=@QiI@JedFMJp%d bDxlj(=fg=ys1NXq2^>XvHM!FFX2Jgh<@fFq -- GitLab From 7327027672997bee81dd64d3c04be024ca741f0b Mon Sep 17 00:00:00 2001 From: Timo Koch Date: Thu, 21 Sep 2017 10:55:59 +0200 Subject: [PATCH 21/42] ex2 fix link readme --- tutorial/ex2/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tutorial/ex2/README.md b/tutorial/ex2/README.md index df76d44fc1..43a12eb611 100644 --- a/tutorial/ex2/README.md +++ b/tutorial/ex2/README.md @@ -2,7 +2,7 @@ ## Problem set-up -The problem setup is identical to the previous [_exercise 1_](https://git.iws.uni-stuttgart.de/dumux-repositories/dumux/blob/6c2ca5dd000599f793f89fe5e3fc69ef9c9d8b73/tutorial/ex1/README.md) with a lower injection rate of 1e-6 kg/(m*s) so that diffusion plays a more dominant role in the transport process. +The problem setup is identical to the previous [_exercise 1_](../ex1/README.md) with a lower injection rate of 1e-6 kg/(m*s) so that diffusion plays a more dominant role in the transport process. ## Preparing the exercise -- GitLab From 999622f07fb32291149d4c2ee2ed5480ae8b0ec4 Mon Sep 17 00:00:00 2001 From: Timo Koch Date: Thu, 21 Sep 2017 11:07:03 +0200 Subject: [PATCH 22/42] ex2 add some space --- tutorial/ex2/README.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tutorial/ex2/README.md b/tutorial/ex2/README.md index 43a12eb611..b9a2b95a74 100644 --- a/tutorial/ex2/README.md +++ b/tutorial/ex2/README.md @@ -1,5 +1,5 @@ # Exercise #2 (DuMuX course) - +
## Problem set-up The problem setup is identical to the previous [_exercise 1_](../ex1/README.md) with a lower injection rate of 1e-6 kg/(m*s) so that diffusion plays a more dominant role in the transport process. @@ -10,6 +10,7 @@ The problem setup is identical to the previous [_exercise 1_](../ex1/README.md) _Exercise 2_ deals with a two-phase compositional problem (__2p2c__). Goal is to learn how to use compile and runtime parameters and the _DuMuX property system_. +


### 1. Getting familiar with the code Locate all the files you will need for this exercise @@ -21,6 +22,8 @@ Locate all the files you will need for this exercise * a custom __local residual__ in: `mylocalresidual.hh` * a custom __material law__ in:: `mymateriallaw.hh` + +


### 2. Compiling and running the program * Change to the build-directory @@ -45,6 +48,7 @@ executable, DuMuX will find it automatically. If gnuplot is installed on your system, you should see a plot of the capillary pressure - saturation relationship. +


### 3. Implement and use a different material law DuMuX uses the term _material law_ to describe the law used to compute @@ -70,6 +74,7 @@ SET_PROP(InjectionSpatialParams, MaterialLaw) Verify your changes by recompiling and running the program. You should see a plot of your new function. +


### 4. Implement your own local residual Most types in DuMuX are properties that can be changed just like the material law. In the following task we implement our own 2p2c local residual, i.e. the class that computes the element residual in every Newton step. The file `mylocalresidual.hh` contains a copy of the original local residual class used for the 2p2c model renamed to `template class MyTwoPTwoCLocalResidual`. -- GitLab From 88edfc4c3786eca6f1b56bb9683f61589f06b042 Mon Sep 17 00:00:00 2001 From: Timo Koch Date: Thu, 21 Sep 2017 11:11:30 +0200 Subject: [PATCH 23/42] ex2 add spacing --- tutorial/ex2/README.md | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/tutorial/ex2/README.md b/tutorial/ex2/README.md index b9a2b95a74..3b5f269c88 100644 --- a/tutorial/ex2/README.md +++ b/tutorial/ex2/README.md @@ -1,5 +1,5 @@ # Exercise #2 (DuMuX course) -
+
## Problem set-up The problem setup is identical to the previous [_exercise 1_](../ex1/README.md) with a lower injection rate of 1e-6 kg/(m*s) so that diffusion plays a more dominant role in the transport process. @@ -10,8 +10,9 @@ The problem setup is identical to the previous [_exercise 1_](../ex1/README.md) _Exercise 2_ deals with a two-phase compositional problem (__2p2c__). Goal is to learn how to use compile and runtime parameters and the _DuMuX property system_. -


-### 1. Getting familiar with the code +

+### Task 1: Getting familiar with the code +
Locate all the files you will need for this exercise * The __main file__: `exercise2.cc` @@ -23,8 +24,9 @@ Locate all the files you will need for this exercise * a custom __material law__ in:: `mymateriallaw.hh` -


-### 2. Compiling and running the program +


+### Task 2: Compiling and running the program +
* Change to the build-directory @@ -48,8 +50,9 @@ executable, DuMuX will find it automatically. If gnuplot is installed on your system, you should see a plot of the capillary pressure - saturation relationship. -


-### 3. Implement and use a different material law +


+### Task 3: Implement and use a different material law +
DuMuX uses the term _material law_ to describe the law used to compute * pc-Sw relations @@ -74,8 +77,9 @@ SET_PROP(InjectionSpatialParams, MaterialLaw) Verify your changes by recompiling and running the program. You should see a plot of your new function. -


-### 4. Implement your own local residual +


+### Task 4: Implement your own local residual +
Most types in DuMuX are properties that can be changed just like the material law. In the following task we implement our own 2p2c local residual, i.e. the class that computes the element residual in every Newton step. The file `mylocalresidual.hh` contains a copy of the original local residual class used for the 2p2c model renamed to `template class MyTwoPTwoCLocalResidual`. -- GitLab From d8bd4aefbd0c57537cf9ce94ff4ac66fdcee3f98 Mon Sep 17 00:00:00 2001 From: Katharina Heck Date: Thu, 21 Sep 2017 11:13:45 +0200 Subject: [PATCH 24/42] [exercise1] change readme to correct value --- tutorial/ex1/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tutorial/ex1/README.md b/tutorial/ex1/README.md index dbd4c495a3..089d2e4c0a 100644 --- a/tutorial/ex1/README.md +++ b/tutorial/ex1/README.md @@ -51,7 +51,7 @@ In the input file `exercise1.input` you can find the following section ```ini [SpatialParams] -EntryPressureFine = 1e4 +EntryPressureFine = 4.5e4 EntryPressureCoarse = 1e4 ``` -- GitLab From 81e6f26f168da9d8b1b508a46aaee5c279820303 Mon Sep 17 00:00:00 2001 From: Kilian Weishaupt Date: Wed, 26 Jul 2017 15:36:56 +0200 Subject: [PATCH 25/42] Fix deprecation warning for Dune MCMG Mapper * Dune > 2.5 uses a new interface and only required GridView as template argument for the mapper type * for the constructor, an additional argument is now required: elementMapper_(gridView, Dune::mcmgElementLayout()) vertexMapper_(gridView, Dune::mcmgVertexLayout()) (cherry picked from commit 6b4dc071dd4e23f02b3605a109b8d1c73ef04c7e) --- dumux/common/intersectionmapper.hh | 8 +++++++- dumux/implicit/problem.hh | 8 ++++++++ dumux/implicit/propertydefaults.hh | 15 +++++++++++++++ dumux/io/vtkmultiwriter.hh | 12 ++++++++++++ dumux/material/spatialparams/gstatrandomfield.hh | 13 ++++++++++++- dumux/porousmediumflow/sequential/properties.hh | 10 ++++++++++ .../porousmediumflow/sequential/variableclass.hh | 12 ++++++++++-- test/geomechanics/el2p/el2pproblem.hh | 11 ++++++++++- 8 files changed, 84 insertions(+), 5 deletions(-) diff --git a/dumux/common/intersectionmapper.hh b/dumux/common/intersectionmapper.hh index dcee8ab505..fadbd0422f 100644 --- a/dumux/common/intersectionmapper.hh +++ b/dumux/common/intersectionmapper.hh @@ -24,6 +24,8 @@ #include #include +#include + /*! * \file * \brief defines an intersection mapper for mapping of global DOFs assigned @@ -44,7 +46,11 @@ class IntersectionMapper enum {dim=Grid::dimension}; typedef typename Grid::template Codim<0>::Entity Element; typedef typename GridView::Intersection Intersection; - typedef Dune::MultipleCodimMultipleGeomTypeMapper ElementMapper; +#if DUNE_VERSION_NEWER(DUNE_COMMON,2,6) + using ElementMapper = Dune::MultipleCodimMultipleGeomTypeMapper; +#else + using ElementMapper = Dune::MultipleCodimMultipleGeomTypeMapper; +#endif public: IntersectionMapper(const GridView& gridview) diff --git a/dumux/implicit/problem.hh b/dumux/implicit/problem.hh index 81e9c32659..d940ba1e14 100644 --- a/dumux/implicit/problem.hh +++ b/dumux/implicit/problem.hh @@ -30,6 +30,8 @@ #include #include +#include + namespace Dumux { /*! @@ -103,11 +105,17 @@ public: : gridView_(gridView) , bBoxMin_(std::numeric_limits::max()) , bBoxMax_(-std::numeric_limits::max()) +#if DUNE_VERSION_NEWER(DUNE_COMMON,2,6) + , elementMapper_(gridView, Dune::mcmgElementLayout()) + , vertexMapper_(gridView, Dune::mcmgVertexLayout()) +#else , elementMapper_(gridView) , vertexMapper_(gridView) +#endif , timeManager_(&timeManager) , newtonMethod_(asImp_()) , newtonCtl_(asImp_()) + { // calculate the bounding box of the local partition of the grid view for (const auto& vertex : vertices(gridView)) { diff --git a/dumux/implicit/propertydefaults.hh b/dumux/implicit/propertydefaults.hh index 8cc5e846ac..b83e553f49 100644 --- a/dumux/implicit/propertydefaults.hh +++ b/dumux/implicit/propertydefaults.hh @@ -41,6 +41,8 @@ #include "localjacobian.hh" #include "volumevariables.hh" +#include + namespace Dumux { // forward declarations @@ -71,16 +73,29 @@ SET_TYPE_PROP(ImplicitBase, NewtonMethod, NewtonMethod); SET_TYPE_PROP(ImplicitBase, NewtonController, NewtonController); //! Mapper for the grid view's vertices. +#if DUNE_VERSION_NEWER(DUNE_COMMON,2,6) +SET_TYPE_PROP(ImplicitBase, + VertexMapper, + Dune::MultipleCodimMultipleGeomTypeMapper); +#else SET_TYPE_PROP(ImplicitBase, VertexMapper, Dune::MultipleCodimMultipleGeomTypeMapper); +#endif + //! Mapper for the grid view's elements. +#if DUNE_VERSION_NEWER(DUNE_COMMON,2,6) +SET_TYPE_PROP(ImplicitBase, + ElementMapper, + Dune::MultipleCodimMultipleGeomTypeMapper); +#else SET_TYPE_PROP(ImplicitBase, ElementMapper, Dune::MultipleCodimMultipleGeomTypeMapper); +#endif //! Set the BaseModel to ImplicitModel SET_TYPE_PROP(ImplicitBase, BaseModel, ImplicitModel); diff --git a/dumux/io/vtkmultiwriter.hh b/dumux/io/vtkmultiwriter.hh index cb7597643f..c7e6744195 100644 --- a/dumux/io/vtkmultiwriter.hh +++ b/dumux/io/vtkmultiwriter.hh @@ -38,6 +38,8 @@ #include +#include + #if HAVE_MPI #include #endif @@ -56,8 +58,13 @@ class VtkMultiWriter { enum { dim = GridView::dimension }; +#if DUNE_VERSION_NEWER(DUNE_COMMON,2,6) + typedef Dune::MultipleCodimMultipleGeomTypeMapper VertexMapper; + typedef Dune::MultipleCodimMultipleGeomTypeMapper ElementMapper; +#else typedef Dune::MultipleCodimMultipleGeomTypeMapper VertexMapper; typedef Dune::MultipleCodimMultipleGeomTypeMapper ElementMapper; +#endif public: typedef Dune::VTKWriter VtkWriter; @@ -65,8 +72,13 @@ public: const std::string &simName = "", std::string multiFileName = "") : gridView_(gridView) +#if DUNE_VERSION_NEWER(DUNE_COMMON,2,6) + , elementMapper_(gridView, Dune::mcmgElementLayout()) + , vertexMapper_(gridView, Dune::mcmgVertexLayout()) +#else , elementMapper_(gridView) , vertexMapper_(gridView) +#endif { simName_ = (simName.empty())?"sim":simName; multiFileName_ = multiFileName; diff --git a/dumux/material/spatialparams/gstatrandomfield.hh b/dumux/material/spatialparams/gstatrandomfield.hh index c7dbe5e552..fbe0924f75 100644 --- a/dumux/material/spatialparams/gstatrandomfield.hh +++ b/dumux/material/spatialparams/gstatrandomfield.hh @@ -30,6 +30,8 @@ #include #include +#include + namespace Dumux { @@ -54,7 +56,11 @@ class GstatRandomField using DataVector = std::vector; using Element = typename GridView::Traits::template Codim<0>::Entity; +#if DUNE_VERSION_NEWER(DUNE_COMMON,2,6) + using ElementMapper = Dune::MultipleCodimMultipleGeomTypeMapper; +#else using ElementMapper = Dune::MultipleCodimMultipleGeomTypeMapper; +#endif public: // Add field types if you want to implement e.g. tensor permeabilities. @@ -66,7 +72,12 @@ public: * \param gridView the used gridView */ GstatRandomField(const GridView& gridView) - : gridView_(gridView), elementMapper_(gridView), + : gridView_(gridView), +#if DUNE_VERSION_NEWER(DUNE_COMMON,2,6) + elementMapper_(gridView, Dune::mcmgElementLayout()), +#else + elementMapper_(gridView), +#endif data_(gridView.size(0)) {} /*! diff --git a/dumux/porousmediumflow/sequential/properties.hh b/dumux/porousmediumflow/sequential/properties.hh index 09cfaa0a7a..205cdaf30c 100644 --- a/dumux/porousmediumflow/sequential/properties.hh +++ b/dumux/porousmediumflow/sequential/properties.hh @@ -24,6 +24,8 @@ #include #include +#include + /*! * \ingroup Sequential * \ingroup IMPETProperties @@ -136,12 +138,20 @@ public: /*! * \brief Mapper for the grid view's vertices. */ +#if DUNE_VERSION_NEWER(DUNE_COMMON,2,6) + using VertexMapper = Dune::MultipleCodimMultipleGeomTypeMapper; +#else typedef Dune::MultipleCodimMultipleGeomTypeMapper VertexMapper; +#endif /*! * \brief Mapper for the grid view's elements. */ +#if DUNE_VERSION_NEWER(DUNE_COMMON,2,6) + using ElementMapper = Dune::MultipleCodimMultipleGeomTypeMapper; +#else typedef Dune::MultipleCodimMultipleGeomTypeMapper ElementMapper; +#endif /*! * \brief The type of a solution at a fixed time. diff --git a/dumux/porousmediumflow/sequential/variableclass.hh b/dumux/porousmediumflow/sequential/variableclass.hh index 25a1e17554..289b1659fd 100644 --- a/dumux/porousmediumflow/sequential/variableclass.hh +++ b/dumux/porousmediumflow/sequential/variableclass.hh @@ -21,6 +21,8 @@ #include "properties.hh" +#include + // for parallelization //#include @@ -77,10 +79,16 @@ public: * @param gridView a DUNE gridview object corresponding to diffusion and transport equation */ VariableClass(const GridView& gridView) : - gridView_(gridView), elementMapper_(gridView), vertexMapper_(gridView) + gridView_(gridView), +#if DUNE_VERSION_NEWER(DUNE_COMMON,2,6) + elementMapper_(gridView, Dune::mcmgElementLayout()), + vertexMapper_(gridView, Dune::mcmgVertexLayout()) +#else + elementMapper_(gridView), + vertexMapper_(gridView) +#endif {} - //! Initializes the variable class /*! Method initializes the cellData vector. * Should be called from problem init() diff --git a/test/geomechanics/el2p/el2pproblem.hh b/test/geomechanics/el2p/el2pproblem.hh index ae4f7fe3fe..f87399f2e4 100644 --- a/test/geomechanics/el2p/el2pproblem.hh +++ b/test/geomechanics/el2p/el2pproblem.hh @@ -34,6 +34,8 @@ #include "el2pco2tables.hh" #include "el2pspatialparams.hh" +#include + namespace Dumux { template @@ -764,7 +766,14 @@ public: * * \param gridView The grid view */ - InitialPressSat(const GridView & gridView) : BaseT(gridView) , gridView_(gridView), vertexMapper_(gridView) + InitialPressSat(const GridView & gridView) + : BaseT(gridView) + , gridView_(gridView) +#if DUNE_VERSION_NEWER(DUNE_COMMON,2,6) + , vertexMapper_(gridView, Dune::mcmgVertexLayout()) +#else + , vertexMapper_(gridView) +#endif { // resize the pressure field vector with the number of vertices pInit_.resize(gridView.size(GridView::dimension)); -- GitLab From 0ba2ceffb45c0ca236ad17c801ae7e1ae2557995 Mon Sep 17 00:00:00 2001 From: Timo Koch Date: Thu, 21 Sep 2017 11:41:42 +0200 Subject: [PATCH 26/42] Fix reference element depr warning for dune 2.6 --- dumux/implicit/model.hh | 3 +-- dumux/porousmediumflow/implicit/velocityoutput.hh | 4 +--- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/dumux/implicit/model.hh b/dumux/implicit/model.hh index 8edcd96150..b6759fdac3 100644 --- a/dumux/implicit/model.hh +++ b/dumux/implicit/model.hh @@ -69,7 +69,6 @@ class ImplicitModel typedef typename GridView::template Codim<0>::Entity Element; typedef typename Dune::ReferenceElements ReferenceElements; - typedef typename Dune::ReferenceElement ReferenceElement; enum { isBox = GET_PROP_VALUE(TypeTag, ImplicitIsBox) }; enum { dofCodim = isBox ? dim : 0 }; @@ -959,7 +958,7 @@ protected: for (const auto& element : elements(gridView_())) { Dune::GeometryType geomType = element.geometry().type(); - const ReferenceElement &refElement = ReferenceElements::general(geomType); + const auto refElement = ReferenceElements::general(geomType); for (const auto& intersection : intersections(gridView_(), element)) { if (intersection.boundary()) { diff --git a/dumux/porousmediumflow/implicit/velocityoutput.hh b/dumux/porousmediumflow/implicit/velocityoutput.hh index 8f386f1042..851f666c4e 100644 --- a/dumux/porousmediumflow/implicit/velocityoutput.hh +++ b/dumux/porousmediumflow/implicit/velocityoutput.hh @@ -66,7 +66,6 @@ class ImplicitVelocityOutput typedef Dune::FieldVector GlobalPosition; typedef typename Dune::ReferenceElements ReferenceElements; - typedef typename Dune::ReferenceElement ReferenceElement; enum { isBox = GET_PROP_VALUE(TypeTag, ImplicitIsBox) }; enum { dofCodim = isBox ? dim : 0 }; @@ -145,8 +144,7 @@ public: const auto geometry = element.geometry(); Dune::GeometryType geomType = geometry.type(); - const ReferenceElement &referenceElement - = ReferenceElements::general(geomType); + const auto referenceElement = ReferenceElements::general(geomType); const Dune::FieldVector& localPos = referenceElement.position(0, 0); -- GitLab From d41087fe9a5567e3c43eadec0ae21db82b312c29 Mon Sep 17 00:00:00 2001 From: Timo Koch Date: Thu, 21 Sep 2017 13:22:55 +0200 Subject: [PATCH 27/42] Update README.md ex1 --- tutorial/ex1/README.md | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/tutorial/ex1/README.md b/tutorial/ex1/README.md index 089d2e4c0a..fd88020936 100644 --- a/tutorial/ex1/README.md +++ b/tutorial/ex1/README.md @@ -1,9 +1,9 @@ # Exercise #1 (DuMuX course) - +
## Problem set-up -N2 is injected in an aquifer previously saturated with water with an injection rate of $`0.001~kg/m*s`$. -The aquifer is situated 2700 m below see level and the domain size is 60 m x 40 m. It consists of two layers, a moderately permeable one ($`\Omega 1`$) and a lower permeable one ($`\Omega 2`$). +N2 is injected in an aquifer previously saturated with water with an injection rate of 0.001 kg/m*s. +The aquifer is situated 2700 m below see level and the domain size is 60 m x 40 m. It consists of two layers, a moderately permeable one ($`\Omega_1`$) and a lower permeable one ($`\Omega_2`$). @@ -13,7 +13,9 @@ The aquifer is situated 2700 m below see level and the domain size is 60 m x 40 _Exercise 1_ deals with two problems: a two-phase immiscible problem (__2p__) and a two-phase compositional problem (__2p2c__). They both set up the same scenario with the difference that the 2p2c assumes a miscible fluid state for the two fluids (water and gaseous N2) and the 2p model assumes an immiscible fluid state. -### 1. Getting familiar with the code +

+### Task 1: Getting familiar with the code +
Locate all the files you will need for this exercise * The __main file__ for the __2p__ problem: `exercise1_2p.cc` @@ -23,8 +25,9 @@ Locate all the files you will need for this exercise * The shared __spatial parameters file__: `injection2pspatialparams.hh` * The shared __input file__: `exercise1.input` - -### 2. Compiling and running an executable +


+### Task 2: Compiling and running an executable +
* Change to the build-directory @@ -45,7 +48,9 @@ make exercise1_2p exercise1_2p2c ./exercise1_2p2c exercise1.input ``` -### 3. Changing input parameters +


+### Task 3: Changing input parameters +
In the input file `exercise1.input` you can find the following section @@ -57,7 +62,9 @@ EntryPressureCoarse = 1e4 * Change the values for the fine entry pressure in the input file to a lower value and compare the results with the previous solution. You don't need to recompile the executable. -### 4. Runtime parameters +


+### Task 4: Runtime parameters +
The injection rate is currently hard-coded in `injection2pproblem.hh`. @@ -85,7 +92,9 @@ Note that due to the way the macro works, the names are specified as plain text Again, you don't need to recompile the program. +


### 5. Setting up a new executable (for a non-isothermal simulation) +
* Set up a new cc file called `exercise1_2pni.cc` by copying and renaming `exercise1_2p.cc` @@ -108,7 +117,9 @@ make # should rerun cmake make injection2pniproblem # builds new executable ``` +


### 6. Setting up a non-isothermal __2pni__ test problem +
* Open the file `injection2pniproblem.hh`. It is a copy of the `injection2pproblem.hh` with some useful comments on how to implement a non-isothermal model. Look for comments containing -- GitLab From e6805985b8233993bbe8d7a8e6b417931b7d302f Mon Sep 17 00:00:00 2001 From: Timo Koch Date: Thu, 21 Sep 2017 19:51:08 +0200 Subject: [PATCH 28/42] Finish ex2 files and test --- tutorial/CMakeLists.txt | 1 + tutorial/ex2/exercise2.input | 21 +- tutorial/ex2/injection2p2cproblem.hh | 265 ++++----- tutorial/ex2/injection2p2cspatialparams.hh | 221 +++++++ tutorial/ex2/mylocalresidual.hh | 535 +++++++++++++++++ tutorial/ex2/mymateriallaw.hh | 115 ++++ tutorial/solution/ex2/injection2p2cproblem.hh | 318 ++++++++++ .../ex2/injection2p2cspatialparams.hh} | 184 +++--- tutorial/solution/ex2/mylocalresidual.hh | 545 ++++++++++++++++++ tutorial/solution/ex2/mymateriallaw.hh | 115 ++++ 10 files changed, 2048 insertions(+), 272 deletions(-) create mode 100644 tutorial/ex2/injection2p2cspatialparams.hh create mode 100644 tutorial/ex2/mylocalresidual.hh create mode 100644 tutorial/ex2/mymateriallaw.hh create mode 100644 tutorial/solution/ex2/injection2p2cproblem.hh rename tutorial/{ex2/injection2pspatialparams.hh => solution/ex2/injection2p2cspatialparams.hh} (54%) create mode 100644 tutorial/solution/ex2/mylocalresidual.hh create mode 100644 tutorial/solution/ex2/mymateriallaw.hh diff --git a/tutorial/CMakeLists.txt b/tutorial/CMakeLists.txt index 546d7e25c8..72c0c32f69 100644 --- a/tutorial/CMakeLists.txt +++ b/tutorial/CMakeLists.txt @@ -1,4 +1,5 @@ add_subdirectory(ex1) +add_subdirectory(ex2) add_subdirectory(ex3) add_subdirectory(tutorial_implicit) add_subdirectory(tutorial_sequential) diff --git a/tutorial/ex2/exercise2.input b/tutorial/ex2/exercise2.input index a4e055be8c..c7149509ad 100755 --- a/tutorial/ex2/exercise2.input +++ b/tutorial/ex2/exercise2.input @@ -1,6 +1,6 @@ [TimeManager] -DtInitial = 250 # [s] -TEnd = 1e7 # [s] +DtInitial = 3600 # in seconds +TEnd = 3.154e9 # in seconds, i.e ten years [Grid] LowerLeft = 0 0 @@ -8,11 +8,18 @@ UpperRight = 60 40 Cells = 24 16 [Problem] -MaxDepth = 2700.0 +Name = infiltration +OnlyPlotMaterialLaws = true +AquiferDepth = 2700.0 # m +TotalAreaSpecificInflow = 1e-4 # kg / (s*m^2) +InjectionDuration = 2.628e6 # in seconds, i.e. one month -[Newton] -WriteConvergence = 1 # write convergence behaviour to disk? +# TODO: dumux-course-task +# Set Problem.EnableGravity +# Set Problem.EnableDiffusion [SpatialParams] -EntryPressureFine = 4.5e4 -EntryPressureCoarse = 1e4 +PermeabilityAquitard = 1e-15 # m^2 +EntryPressureAquitard = 4.5e4 # Pa +PermeabilityAquifer = 1e-12 # m^2 +EntryPressureAquifer = 1e4 # Pa diff --git a/tutorial/ex2/injection2p2cproblem.hh b/tutorial/ex2/injection2p2cproblem.hh index a63bc73d1c..cf45851a5b 100644 --- a/tutorial/ex2/injection2p2cproblem.hh +++ b/tutorial/ex2/injection2p2cproblem.hh @@ -28,16 +28,23 @@ #include #include -#include "injection2pspatialparams.hh" +#include "injection2p2cspatialparams.hh" + +// TODO: dumux-course-task +// Include the local residual header namespace Dumux { +// foward declaration template class Injection2p2cProblem; +// setup property TypeTag namespace Properties { +// TODO: dumux-course-task +// inherit from MyLocalResidualParams NEW_TYPE_TAG(Injection2p2cProblem, INHERITS_FROM(TwoPTwoC, InjectionSpatialParams)); NEW_TYPE_TAG(Injection2p2cBoxProblem, INHERITS_FROM(BoxModel, Injection2p2cProblem)); NEW_TYPE_TAG(Injection2p2pcCCProblem, INHERITS_FROM(CCModel, Injection2p2cProblem)); @@ -48,15 +55,18 @@ SET_TYPE_PROP(Injection2p2cProblem, Grid, Dune::YaspGrid<2>); // Set the problem property SET_TYPE_PROP(Injection2p2cProblem, Problem, Injection2p2cProblem); +// TODO: dumux-course-task +// change the local residual type to MyTwoPTwoCLocalResidual + // Set fluid configuration SET_TYPE_PROP(Injection2p2cProblem, FluidSystem, - FluidSystems::H2ON2); + FluidSystems::H2ON2); // Define whether mole(true) or mass (false) fractions are used SET_BOOL_PROP(Injection2p2cProblem, UseMoles, true); -} +} // end namespace Properties /*! * \ingroup TwoPTwoCModel @@ -67,18 +77,18 @@ SET_BOOL_PROP(Injection2p2cProblem, UseMoles, true); * permeable one (\f$ K=10e-12\f$) for \f$ y<22m\f$ and one with a lower permeablility (\f$ K=10e-13\f$) * in the rest of the domain. * - * A mixture of Nitrogen and Water vapor, which is composed according to the prevailing conditions (temperature, pressure) - * enters a water-filled aquifer. This is realized with a solution-dependent Neumann boundary condition at the right boundary - * (\f$ 7m./exercise1_2p2c -parameterFile exercise1.input> */ template class Injection2p2cProblem : public ImplicitPorousMediaProblem @@ -89,45 +99,16 @@ class Injection2p2cProblem : public ImplicitPorousMediaProblem typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; typedef typename GET_PROP_TYPE(TypeTag, FluidSystem) FluidSystem; - enum { - // Grid and world dimension - dim = GridView::dimension, - dimWorld = GridView::dimensionworld - }; + // grid world dimension + static constexpr auto dimWorld = GridView::dimensionworld; - // copy some indices for convenience typedef typename GET_PROP_TYPE(TypeTag, Indices) Indices; - enum { - wPhaseIdx = Indices::wPhaseIdx, - nPhaseIdx = Indices::nPhaseIdx, - - - wCompIdx = FluidSystem::wCompIdx, - nCompIdx = FluidSystem::nCompIdx, - - contiH2OEqIdx = Indices::contiWEqIdx, - contiN2EqIdx = Indices::contiNEqIdx - }; - - typedef typename GET_PROP_TYPE(TypeTag, PrimaryVariables) PrimaryVariables; - typedef typename GET_PROP_TYPE(TypeTag, ElementVolumeVariables) ElementVolumeVariables; typedef typename GET_PROP_TYPE(TypeTag, BoundaryTypes) BoundaryTypes; typedef typename GET_PROP_TYPE(TypeTag, TimeManager) TimeManager; - - typedef typename GridView::template Codim<0>::Entity Element; - typedef typename GridView::template Codim::Entity Vertex; - typedef typename GridView::Intersection Intersection; - - typedef typename GET_PROP_TYPE(TypeTag, FVElementGeometry) FVElementGeometry; - + typedef typename GET_PROP_TYPE(TypeTag, MaterialLaw) MaterialLaw; typedef Dune::FieldVector GlobalPosition; - enum { isBox = GET_PROP_VALUE(TypeTag, ImplicitIsBox) }; - - //! property that defines whether mole or mass fractions are used - static const bool useMoles = GET_PROP_VALUE(TypeTag, UseMoles); - public: /*! * \brief The constructor @@ -135,51 +116,47 @@ public: * \param timeManager The time manager * \param gridView The grid view */ - Injection2p2cProblem(TimeManager &timeManager, - const GridView &gridView) - : ParentType(timeManager, gridView) + Injection2p2cProblem(TimeManager &timeManager, const GridView &gridView) + : ParentType(timeManager, gridView) { - maxDepth_ = GET_RUNTIME_PARAM(TypeTag, Scalar, Problem.MaxDepth); - // initialize the tables of the fluid system FluidSystem::init(/*tempMin=*/273.15, - /*tempMax=*/423.15, - /*numTemp=*/50, - /*pMin=*/0.0, - /*pMax=*/30e6, - /*numP=*/300); - - //stateing in the console whether mole or mass fractions are used - if(useMoles) - { - std::cout<<"problem uses mole-fractions"<model().globalPhaseStorage(storageW, wPhaseIdx); - this->model().globalPhaseStorage(storageN, nPhaseIdx); + this->model().globalPhaseStorage(storageW, Indices::wPhaseIdx); + this->model().globalPhaseStorage(storageN, Indices::nPhaseIdx); // Write mass balance information for rank 0 - if (this->gridView().comm().rank() == 0) { - std::cout<<"Storage: wetting=[" << storageW << "]" - << " nonwetting=[" << storageN << "]\n"; + if (this->gridView().comm().rank() == 0) + { + std::cout <<"Storage: wetting=[" << storageW << "]" + << " nonwetting=[" << storageN << "]" << std::endl; } } - /*! * \name Problem parameters */ @@ -190,16 +167,14 @@ public: * * This is used as a prefix for files generated by the simulation. */ - const std::string name() const - { return "injection-2p2c"; } + const std::string& name() const + { return name_; } /*! - * \brief Returns the temperature \f$ K \f$ + * \brief Returns the temperature in \f$ K \f$ */ Scalar temperature() const - { - return 273.15 + 30; // [K] - } + { return 273.15 + 30; } /*! * \brief Returns the source term @@ -210,9 +185,7 @@ public: */ void sourceAtPos(PrimaryVariables &values, const GlobalPosition &globalPos) const - { - values = 0; - } + { values = 0; } // \} @@ -231,10 +204,18 @@ public: void boundaryTypesAtPos(BoundaryTypes &values, const GlobalPosition &globalPos) const { - if (globalPos[0] < eps_) + // Set Dirichlet at the bottom of the domain + if (globalPos[dimWorld-1] < eps_) + { values.setAllDirichlet(); + } + + // and Neuman boundary conditions everywhere else + // note that we don't differentiate between Neumann and Robin boundary types else + { values.setAllNeumann(); + } } /*! @@ -246,50 +227,30 @@ public: * \param globalPos The global position */ void dirichletAtPos(PrimaryVariables &values, const GlobalPosition &globalPos) const - { - initial_(values, globalPos); - } + { initialAtPos(values, globalPos); } /*! - * \brief Evaluates the boundary conditions for a Neumann - * boundary segment in dependency on the current solution. + * \brief Evaluates the boundary conditions for a Neumann boundary segment. * * \param values Stores the Neumann values for the conservation equations in * \f$ [ \textnormal{unit of conserved quantity} / (m^(dim-1) \cdot s )] \f$ - * \param element The finite element - * \param fvGeometry The finite volume geometry of the element - * \param intersection The intersection between element and boundary - * \param scvIdx The local index of the sub-control volume - * \param boundaryFaceIdx The index of the boundary face - * \param elemVolVars All volume variables for the element - * - * This method is used for cases, when the Neumann condition depends on the - * solution and requires some quantities that are specific to the fully-implicit method. - * The \a values store the mass flux of each phase normal to the boundary. - * Negative values indicate an inflow. + * \param globalPos The globalPosition of the boundary interface */ - void solDependentNeumann(PrimaryVariables &values, - const Element &element, - const FVElementGeometry &fvGeometry, - const Intersection &intersection, - const int scvIdx, - const int boundaryFaceIdx, - const ElementVolumeVariables &elemVolVars) const + void neumannAtPos(PrimaryVariables &values, + const GlobalPosition &globalPos) const { - values = 0; - - GlobalPosition globalPos; - if (isBox) - globalPos = element.geometry().corner(scvIdx); - else - globalPos = intersection.geometry().center(); - - Scalar injectedPhaseMass = 1e-3; - Scalar moleFracW = elemVolVars[scvIdx].moleFraction(nPhaseIdx, wCompIdx); - if (globalPos[1] < 15 + eps_ && globalPos[1] > 7 -eps_) { - values[contiN2EqIdx] = -(1-moleFracW)*injectedPhaseMass/FluidSystem::molarMass(nCompIdx); //mole/(m^2*s) -> kg/(s*m^2) - values[contiH2OEqIdx] = -moleFracW*injectedPhaseMass/FluidSystem::molarMass(wCompIdx); //mole/(m^2*s) -> kg/(s*m^2) - } + // initialize values to zero, i.e. no-flow Neumann boundary conditions + values = 0; + + //if we are inside the injection zone set inflow Neumann boundary conditions + if (this->timeManager().time() + this->timeManager().timeStepSize() < injectionDuration_ + && globalPos[1] < 15 + eps_ && globalPos[1] > 7 - eps_ && globalPos[0] > 0.9*this->bBoxMax()[0]) + { + // set the Neumann values for the Nitrogen component balance + // convert from units kg/(s*m^2) to mole/(s*m^2) + values[Indices::contiNEqIdx] = -totalAreaSpecificInflow_/FluidSystem::molarMass(FluidSystem::nCompIdx); + values[Indices::contiWEqIdx] = 0.0; + } } // \} @@ -308,60 +269,48 @@ public: */ void initialAtPos(PrimaryVariables &values, const GlobalPosition &globalPos) const { - initial_(values, globalPos); + // 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]); + + // initially we have some nitrogen dissolved + // saturation mole fraction would be + // moleFracLiquidN2 = (pw + pc + p_vap^sat)/henry; + const Scalar moleFracLiquidN2 = pw*0.95/BinaryCoeff::H2O_N2::henry(temperature()); + + // note that because we start with a single phase system the primary variables + // are pl and x^w_N2. This will switch as soon after we start injecting to a two + // phase system so the primary variables will be pl and Sn (non-wetting saturation). + values[Indices::switchIdx] = moleFracLiquidN2; + values[Indices::pressureIdx] = pw; } /*! * \brief Return the initial phase state inside a control volume. * * \param globalPos The global position + * \note we start with a single phase system */ int initialPhasePresenceAtPos(const GlobalPosition &globalPos) const { return Indices::wPhaseOnly; } // \} -private: - /*! - * \brief Evaluates the initial values for a control volume - * - * The internal method for the initial condition - * - * \param values Stores the initial values for the conservation equations in - * \f$ [ \textnormal{unit of primary variables} ] \f$ - * \param globalPos The global position - */ - void initial_(PrimaryVariables &values, - const GlobalPosition &globalPos) const - { - Scalar densityW = FluidSystem::H2O::liquidDensity(temperature(), 1e5); - - Scalar pl = 1e5 - densityW*this->gravity()[1]*(maxDepth_ - globalPos[1]); - Scalar moleFracLiquidN2 = pl*0.95/BinaryCoeff::H2O_N2::henry(temperature()); - Scalar moleFracLiquidH2O = 1.0 - moleFracLiquidN2; - - Scalar meanM = - FluidSystem::molarMass(wCompIdx)*moleFracLiquidH2O + - FluidSystem::molarMass(nCompIdx)*moleFracLiquidN2; - if(useMoles) - { - //mole-fraction formulation - values[Indices::switchIdx] = moleFracLiquidN2; - } - else - { - //mass fraction formulation - Scalar massFracLiquidN2 = moleFracLiquidN2*FluidSystem::molarMass(nCompIdx)/meanM; - values[Indices::switchIdx] = massFracLiquidN2; - } - values[Indices::pressureIdx] = pl; - } - + //! If we should write restart files + bool shouldWriteRestartFile() const + { return false; } +private: static constexpr Scalar eps_ = 1e-6; - Scalar maxDepth_; - + std::string name_; //! Problem name + Scalar aquiferDepth_; //! Depth of the aquifer in m + Scalar totalAreaSpecificInflow_; //! Area specific inflow rate in mole/(s*m^2) + Scalar injectionDuration_; //! Duration of the injection in seconds }; -} //end namespace + +} // end namespace Dumux #endif diff --git a/tutorial/ex2/injection2p2cspatialparams.hh b/tutorial/ex2/injection2p2cspatialparams.hh new file mode 100644 index 0000000000..aac0effb44 --- /dev/null +++ b/tutorial/ex2/injection2p2cspatialparams.hh @@ -0,0 +1,221 @@ +// -*- 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 Definition of the spatial parameters for the injection problem + * which uses the isothermal two-phase two-component + * fully implicit model. + */ + +#ifndef DUMUX_INJECTION_SPATIAL_PARAMS_HH +#define DUMUX_INJECTION_SPATIAL_PARAMS_HH + +#include +#include +#include +// TODO: dumux-course-task +// Inlcude your own material law + +#include +#include + +#include + +namespace Dumux +{ + +// forward declaration +template +class InjectionSpatialParams; + +// setup property TypeTag +namespace Properties +{ +// The spatial parameters TypeTag +NEW_TYPE_TAG(InjectionSpatialParams); + +// Set the spatial parameters +SET_TYPE_PROP(InjectionSpatialParams, SpatialParams, InjectionSpatialParams); + +// TODO: dumux-course-task +// Use your own material law instead +// Set the material law parameterized by absolute saturations +SET_PROP(InjectionSpatialParams, MaterialLaw) +{ + using Scalar = typename GET_PROP_TYPE(TypeTag, Scalar); + using type = EffToAbsLaw>; +}; + +} // end namespace Properties + +/*! + * \ingroup TwoPTwoCModel + * \ingroup ImplicitTestProblems + * \brief Definition of the spatial parameters for the injection problem + * which uses the isothermal two-phase two-component + * fully implicit model. + */ +template +class InjectionSpatialParams : public ImplicitSpatialParams +{ + typedef ImplicitSpatialParams ParentType; + typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; + typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; + typedef typename GridView::ctype CoordinateType; + + enum { + dim=GridView::dimension, + dimWorld=GridView::dimensionworld + }; + + typedef Dune::FieldVector GlobalPosition; + typedef typename GET_PROP_TYPE(TypeTag, FVElementGeometry) FVElementGeometry; + typedef typename GridView::template Codim<0>::Entity Element; + typedef typename GET_PROP_TYPE(TypeTag, MaterialLaw) MaterialLaw; + typedef typename MaterialLaw::Params MaterialLawParams; + +public: + + /*! + * \brief The constructor + * + * \param gridView The grid view + */ + InjectionSpatialParams(const GridView &gridView) + : ParentType(gridView) + { + aquiferHeightFromBottom_ = 30.0; + + // intrinsic permeabilities + aquitardK_ = GET_RUNTIME_PARAM(TypeTag, Scalar, SpatialParams.PermeabilityAquitard); + aquiferK_ = GET_RUNTIME_PARAM(TypeTag, Scalar, SpatialParams.PermeabilityAquifer); + + // porosities + aquitardPorosity_ = 0.2; + aquiferPorosity_ = 0.4; + + // residual saturations + aquitardMaterialParams_.setSwr(0.2); + aquitardMaterialParams_.setSnr(0.0); + aquiferMaterialParams_.setSwr(0.2); + aquiferMaterialParams_.setSnr(0.0); + + // parameters for the Brooks-Corey law + aquitardMaterialParams_.setPe(GET_RUNTIME_PARAM(TypeTag, Scalar, SpatialParams.EntryPressureAquitard)); + aquiferMaterialParams_.setPe(GET_RUNTIME_PARAM(TypeTag, Scalar, SpatialParams.EntryPressureAquifer)); + aquitardMaterialParams_.setLambda(2.0); + aquiferMaterialParams_.setLambda(2.0); + + // plot the material laws using gnuplot and exit + if (GET_RUNTIME_PARAM(TypeTag, bool, Problem.OnlyPlotMaterialLaws)) + { + plotMaterialLaws(); + exit(0); + } + } + + /*! + * \brief Returns the intrinsic permeability tensor \f$[m^2]\f$ + * + * \param element The finite element + * \param fvGeometry The finite volume geometry of the element + * \param scvIdx The local index of the sub-control volume + */ + Scalar intrinsicPermeability(const Element &element, + const FVElementGeometry &fvGeometry, + const int scvIdx) const + { + const GlobalPosition &globalPos = fvGeometry.subContVol[scvIdx].global; + if (isInAquitard_(globalPos)) + return aquitardK_; + return aquiferK_; + } + + /*! + * \brief Returns the porosity \f$[-]\f$ + * + * \param element The finite element + * \param fvGeometry The finite volume geometry of the element + * \param scvIdx The local index of the sub-control volume + */ + Scalar porosity(const Element &element, + const FVElementGeometry &fvGeometry, + const int scvIdx) const + { + const GlobalPosition &globalPos = fvGeometry.subContVol[scvIdx].global; + if (isInAquitard_(globalPos)) + return aquitardPorosity_; + return aquiferPorosity_; + } + + + /*! + * \brief Returns the parameter object for the capillary-pressure/ + * saturation material law + * + * \param element The finite element + * \param fvGeometry The finite volume geometry of the element + * \param scvIdx The local index of the sub-control volume + */ + const MaterialLawParams& materialLawParams(const Element &element, + const FVElementGeometry &fvGeometry, + const int scvIdx) const + { + const GlobalPosition &globalPos = fvGeometry.subContVol[scvIdx].global; + if (isInAquitard_(globalPos)) + return aquitardMaterialParams_; + return aquiferMaterialParams_; + } + + /*! + * \brief Creates a gnuplot output of the pc-Sw curve + */ + void plotMaterialLaws() + { + PlotMaterialLaw plotMaterialLaw; + GnuplotInterface gnuplot; + plotMaterialLaw.addpcswcurve(gnuplot, aquitardMaterialParams_, 0.2, 1.0, "upper layer (fine, aquitard)", "w lp"); + plotMaterialLaw.addpcswcurve(gnuplot, aquiferMaterialParams_, 0.2, 1.0, "lower layer (coarse, aquifer)", "w l"); + gnuplot.setOption("set xrange [0:1]"); + gnuplot.setOption("set label \"residual\\nsaturation\" at 0.1,100000 center"); + gnuplot.plot("pc-Sw"); + } + +private: + + static constexpr Scalar eps_ = 1e-6; + + bool isInAquitard_(const GlobalPosition &globalPos) const + { return globalPos[dimWorld-1] > aquiferHeightFromBottom_ + eps_; } + + Scalar aquitardK_; + Scalar aquiferK_; + Scalar aquiferHeightFromBottom_; + + Scalar aquitardPorosity_; + Scalar aquiferPorosity_; + + MaterialLawParams aquitardMaterialParams_; + MaterialLawParams aquiferMaterialParams_; +}; + +} // end namespace Dumux + +#endif diff --git a/tutorial/ex2/mylocalresidual.hh b/tutorial/ex2/mylocalresidual.hh new file mode 100644 index 0000000000..bcaae17364 --- /dev/null +++ b/tutorial/ex2/mylocalresidual.hh @@ -0,0 +1,535 @@ +// -*- 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 Element-wise calculation of the Jacobian matrix for problems + * using the two-phase two-component fully implicit model. + */ + +#ifndef DUMUX_MY_2P2C_LOCAL_RESIDUAL_HH +#define DUMUX_MY_2P2C_LOCAL_RESIDUAL_HH + +#include + +namespace Dumux +{ + +// TODO: dumux-course-task +// implement new TypeTag MyLocalResidualParams + +/*! + * \ingroup TwoPTwoCModel + * \ingroup ImplicitLocalResidual + * \brief Element-wise calculation of the Jacobian matrix for problems + * using the two-phase two-component fully implicit model. + * + * This class is used to fill the gaps in ImplicitLocalResidual for the + * two-phase two-component flow. + */ +template +class MyTwoPTwoCLocalResidual: public GET_PROP_TYPE(TypeTag, BaseLocalResidual) +{ + protected: + typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; + typedef typename GET_PROP_TYPE(TypeTag, LocalResidual) Implementation; + typedef typename GET_PROP_TYPE(TypeTag, FluidSystem) FluidSystem; + typedef typename GET_PROP_TYPE(TypeTag, PrimaryVariables) PrimaryVariables; + typedef typename GET_PROP_TYPE(TypeTag, FVElementGeometry) FVElementGeometry; + typedef typename GET_PROP_TYPE(TypeTag, VolumeVariables) VolumeVariables; + typedef typename GET_PROP_TYPE(TypeTag, ElementVolumeVariables) ElementVolumeVariables; + typedef typename GET_PROP_TYPE(TypeTag, ElementBoundaryTypes) ElementBoundaryTypes; + typedef typename GET_PROP_TYPE(TypeTag, FluxVariables) FluxVariables; + enum + { + numPhases = GET_PROP_VALUE(TypeTag, NumPhases), + numComponents = GET_PROP_VALUE(TypeTag, NumComponents) + }; + + typedef typename GET_PROP_TYPE(TypeTag, Indices) Indices; + enum + { + contiWEqIdx = Indices::contiWEqIdx, + contiNEqIdx = Indices::contiNEqIdx, + wPhaseIdx = Indices::wPhaseIdx, + nPhaseIdx = Indices::nPhaseIdx, + wCompIdx = Indices::wCompIdx, + nCompIdx = Indices::nCompIdx + }; + + typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; + typedef typename GridView::template Codim<0>::Entity Element; + + static constexpr unsigned int replaceCompEqIdx = GET_PROP_VALUE(TypeTag, ReplaceCompEqIdx); + + //! Property that defines whether mole or mass fractions are used + static const bool useMoles = GET_PROP_VALUE(TypeTag, UseMoles); + + public: + /*! + * \brief Constructor + * + * Sets the mass upwind weight. + */ + MyTwoPTwoCLocalResidual() + { + // retrieve the upwind weight for the mass conservation equations. Use the value + // specified via the property system as default, and overwrite + // it by the run-time parameter from the Dune::ParameterTree + massUpwindWeight_ = GET_PARAM_FROM_GROUP(TypeTag, Scalar, Implicit, MassUpwindWeight); + + // TODO: dumux-course-task + // get parameter Problem.EnableDiffusion + } + + /*! + * \brief Evaluate the storage term of the current solution in a + * single phase. + * + * \param element The element + * \param phaseIdx The index of the fluid phase + */ + void evalPhaseStorage(const Element &element, const int phaseIdx) + { + FVElementGeometry fvGeometry; + fvGeometry.update(this->gridView_(), element); + ElementBoundaryTypes bcTypes; + bcTypes.update(this->problem_(), element, fvGeometry); + ElementVolumeVariables elemVolVars; + elemVolVars.update(this->problem_(), element, fvGeometry, false); + + this->storageTerm_.resize(fvGeometry.numScv); + this->storageTerm_ = 0; + + this->elemPtr_ = &element; + this->fvElemGeomPtr_ = &fvGeometry; + this->bcTypesPtr_ = &bcTypes; + this->prevVolVarsPtr_ = 0; + this->curVolVarsPtr_ = &elemVolVars; + evalPhaseStorage_(phaseIdx); + } + + /*! + * \brief Evaluate the amount of all conservation quantities + * (e.g. phase mass) within a sub-control volume. + * + * \param storage The mass of the component within the sub-control volume + * \param scvIdx The sub-control-volume index + * \param usePrevSol Based on usePrevSol solution of current or previous time step is used + * + * The result should be averaged over the volume (e.g. phase mass + * inside a sub-control volume divided by the volume) + */ + void computeStorage(PrimaryVariables &storage, const int scvIdx, bool usePrevSol) const + { + // if flag usePrevSol is set, the solution from the previous + // time step is used, otherwise the current solution is + // used. The secondary variables are used accordingly. This + // is required to compute the derivative of the storage term + // using the implicit Euler method. + const ElementVolumeVariables &elemVolVars = usePrevSol ? this->prevVolVars_() + : this->curVolVars_(); + const VolumeVariables &volVars = elemVolVars[scvIdx]; + + // compute storage term of all components within all phases + storage = 0; + if(useMoles) // mole-fraction formulation + { + for (unsigned int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) + { + for (unsigned int compIdx = contiCompIdx1_(); compIdx <= contiCompIdx2_(); ++compIdx) + { + unsigned int eqIdx = (compIdx == wCompIdx) ? contiWEqIdx : contiNEqIdx; + storage[eqIdx] += volVars.molarDensity(phaseIdx) + * volVars.saturation(phaseIdx) + * volVars.moleFraction(phaseIdx, compIdx); + } + // this is only processed if one component mass balance equation + // is replaced by the total mass balance equation + if (replaceCompEqIdx < numComponents) + storage[replaceCompEqIdx] += + volVars.molarDensity(phaseIdx) + * volVars.saturation(phaseIdx); + } + storage *= volVars.porosity(); + } + else // mass-fraction formulation + { + for (unsigned int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) + { + for (unsigned int compIdx = contiCompIdx1_(); compIdx <= contiCompIdx2_(); ++compIdx) + { + unsigned int eqIdx = (compIdx == wCompIdx) ? contiWEqIdx : contiNEqIdx; + storage[eqIdx] += volVars.density(phaseIdx) + * volVars.saturation(phaseIdx) + * volVars.massFraction(phaseIdx, compIdx); + } + // this is only processed if one component mass balance equation + // is replaced by the total mass balance equation + if (replaceCompEqIdx < numComponents) + storage[replaceCompEqIdx] += + volVars.density(phaseIdx) + * volVars.saturation(phaseIdx); + } + storage *= volVars.porosity(); + } + } + + /*! + * \brief Evaluates the total flux of all conservation quantities + * over a face of a sub-control volume. + * + * \param flux The flux over the sub-control-volume face for each component + * \param fIdx The index of the sub-control-volume face + * \param onBoundary Evaluate flux at inner sub-control-volume face or on a boundary face + */ + void computeFlux(PrimaryVariables &flux, const int fIdx, bool onBoundary=false) const + { + // update the flux variables + FluxVariables fluxVars; + fluxVars.update(this->problem_(), + this->element_(), + this->fvGeometry_(), + fIdx, + this->curVolVars_(), + onBoundary); + + flux = 0; + + // add advective fluxes + computeAdvectiveFlux(flux, fluxVars); + + // add diffusive fluxes + // TODO: dumux-course-task + // only add diffusive fluxes if diffusion is enabled + } + + /*! + * \brief Evaluates the advective mass flux of all components over + * a face of a sub-control volume. + * + * \param flux The flux over the sub-control-volume face for each component + * \param fluxVars The flux variables at the current sub-control-volume face + */ + void computeAdvectiveFlux(PrimaryVariables &flux, const FluxVariables &fluxVars) const + { + //////// + // advective fluxes of all components in all phases + //////// + + if(useMoles) // mole-fraction formulation + { + for (unsigned int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) + { + // data attached to upstream and the downstream vertices + // of the current phase + const VolumeVariables &up = + this->curVolVars_(fluxVars.upstreamIdx(phaseIdx)); + const VolumeVariables &dn = + this->curVolVars_(fluxVars.downstreamIdx(phaseIdx)); + + for (unsigned int compIdx = contiCompIdx1_(); compIdx <= contiCompIdx2_(); ++compIdx) + { + unsigned int eqIdx = (compIdx == wCompIdx) ? contiWEqIdx : contiNEqIdx; + // add advective flux of current component in current + // phase + if (massUpwindWeight_ > 0.0) + // upstream vertex + flux[eqIdx] += + fluxVars.volumeFlux(phaseIdx) + * massUpwindWeight_ + * up.molarDensity(phaseIdx) + * up.moleFraction(phaseIdx, compIdx); + if (massUpwindWeight_ < 1.0) + // downstream vertex + flux[eqIdx] += + fluxVars.volumeFlux(phaseIdx) + * (1 - massUpwindWeight_) + * dn.molarDensity(phaseIdx) + * dn.moleFraction(phaseIdx, compIdx); + + Valgrind::CheckDefined(fluxVars.volumeFlux(phaseIdx)); + Valgrind::CheckDefined(up.molarDensity(phaseIdx)); + Valgrind::CheckDefined(up.moleFraction(phaseIdx, compIdx)); + Valgrind::CheckDefined(dn.molarDensity(phaseIdx)); + Valgrind::CheckDefined(dn.moleFraction(phaseIdx, compIdx)); + } + // flux of the total mass balance; + // this is only processed if one component mass balance equation + // is replaced by a total mass balance equation + if (replaceCompEqIdx < numComponents) + { + // upstream vertex + if (massUpwindWeight_ > 0.0) + flux[replaceCompEqIdx] += + fluxVars.volumeFlux(phaseIdx) + * massUpwindWeight_ + * up.molarDensity(phaseIdx); + // downstream vertex + if (massUpwindWeight_ < 1.0) + flux[replaceCompEqIdx] += + fluxVars.volumeFlux(phaseIdx) + * (1 - massUpwindWeight_) + * dn.molarDensity(phaseIdx); + Valgrind::CheckDefined(fluxVars.volumeFlux(phaseIdx)); + Valgrind::CheckDefined(up.molarDensity(phaseIdx)); + Valgrind::CheckDefined(dn.molarDensity(phaseIdx)); + + } + + } + } + else // mass-fraction formulation + { + for (unsigned int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) + { + // data attached to upstream and downstream vertices + // of the current phase + const VolumeVariables &up = + this->curVolVars_(fluxVars.upstreamIdx(phaseIdx)); + const VolumeVariables &dn = + this->curVolVars_(fluxVars.downstreamIdx(phaseIdx)); + + for (unsigned int compIdx = contiCompIdx1_(); compIdx <= contiCompIdx2_(); ++compIdx) + { + unsigned int eqIdx = (compIdx == wCompIdx) ? contiWEqIdx : contiNEqIdx; + // add advective flux of current component in current + // phase + if (massUpwindWeight_ > 0.0) + // upstream vertex + flux[eqIdx] += + fluxVars.volumeFlux(phaseIdx) + * massUpwindWeight_ + * up.density(phaseIdx) + * up.massFraction(phaseIdx, compIdx); + if (massUpwindWeight_ < 1.0) + // downstream vertex + flux[eqIdx] += + fluxVars.volumeFlux(phaseIdx) + * (1 - massUpwindWeight_) + * dn.density(phaseIdx) + * dn.massFraction(phaseIdx, compIdx); + + Valgrind::CheckDefined(fluxVars.volumeFlux(phaseIdx)); + Valgrind::CheckDefined(up.density(phaseIdx)); + Valgrind::CheckDefined(up.massFraction(phaseIdx, compIdx)); + Valgrind::CheckDefined(dn.density(phaseIdx)); + Valgrind::CheckDefined(dn.massFraction(phaseIdx, compIdx)); + } + // flux of the total mass balance; + // this is only processed if one component mass balance equation + // is replaced by a total mass balance equation + if (replaceCompEqIdx < numComponents) + { + // upstream vertex + if (massUpwindWeight_ > 0.0) + flux[replaceCompEqIdx] += + fluxVars.volumeFlux(phaseIdx) + * massUpwindWeight_ + * up.density(phaseIdx); + // downstream vertex + if (massUpwindWeight_ < 1.0) + flux[replaceCompEqIdx] += + fluxVars.volumeFlux(phaseIdx) + * (1 - massUpwindWeight_) + * dn.density(phaseIdx); + Valgrind::CheckDefined(fluxVars.volumeFlux(phaseIdx)); + Valgrind::CheckDefined(up.density(phaseIdx)); + Valgrind::CheckDefined(dn.density(phaseIdx)); + + } + + } + } + } + + /*! + * \brief Evaluates the diffusive mass flux of all components over + * a face of a sub-control volume. + * + * \param flux The flux over the sub-control-volume face for each component + * \param fluxVars The flux variables at the current sub-control-volume face + */ + void computeDiffusiveFlux(PrimaryVariables &flux, const FluxVariables &fluxVars) const + + { + if(useMoles) // mole-fraction formulation + { + // add diffusive flux of gas component in liquid phase + Scalar tmp = -(fluxVars.moleFractionGrad(wPhaseIdx)*fluxVars.face().normal) + * fluxVars.porousDiffCoeff(wPhaseIdx) + * fluxVars.molarDensity(wPhaseIdx); + // add the diffusive fluxes only to the component mass balance + if (replaceCompEqIdx != contiNEqIdx) + flux[contiNEqIdx] += tmp; + if (replaceCompEqIdx != contiWEqIdx) + flux[contiWEqIdx] -= tmp; + + // add diffusive flux of liquid component in non-wetting phase + tmp = -(fluxVars.moleFractionGrad(nPhaseIdx)*fluxVars.face().normal) + * fluxVars.porousDiffCoeff(nPhaseIdx) + * fluxVars.molarDensity(nPhaseIdx); + // add the diffusive fluxes only to the component mass balance + if (replaceCompEqIdx != contiWEqIdx) + flux[contiWEqIdx] += tmp; + if (replaceCompEqIdx != contiNEqIdx) + flux[contiNEqIdx] -= tmp; + } + else // mass-fraction formulation + { + // add diffusive flux of gas component in wetting phase + Scalar tmp = -(fluxVars.moleFractionGrad(wPhaseIdx)*fluxVars.face().normal) + * fluxVars.porousDiffCoeff(wPhaseIdx) + * fluxVars.molarDensity(wPhaseIdx); + // add the diffusive fluxes to the component mass balance and total mass balance + if (replaceCompEqIdx < numComponents) + { + flux[replaceCompEqIdx] += tmp * FluidSystem::molarMass(nCompIdx); + flux[replaceCompEqIdx] -= tmp * FluidSystem::molarMass(wCompIdx); + } + if (replaceCompEqIdx != contiWEqIdx) + { + flux[contiWEqIdx] -= tmp * FluidSystem::molarMass(wCompIdx); + } + if (replaceCompEqIdx != contiNEqIdx) + { + flux[contiNEqIdx] += tmp * FluidSystem::molarMass(nCompIdx); + } + + // add diffusive fluxes of liquid component in non-wetting phase + tmp = -(fluxVars.moleFractionGrad(nPhaseIdx)*fluxVars.face().normal) + * fluxVars.porousDiffCoeff(nPhaseIdx) + * fluxVars.molarDensity(nPhaseIdx); + // add the diffusive fluxes to the component mass balance and total mass balance + if (replaceCompEqIdx < numComponents) + { + flux[replaceCompEqIdx] += tmp * FluidSystem::molarMass(wCompIdx); + flux[replaceCompEqIdx] -= tmp * FluidSystem::molarMass(nCompIdx); + } + if (replaceCompEqIdx != contiWEqIdx) + { + flux[contiWEqIdx] += tmp * FluidSystem::molarMass(wCompIdx); + } + if (replaceCompEqIdx != contiNEqIdx) + { + flux[contiNEqIdx] -= tmp * FluidSystem::molarMass(nCompIdx); + } + } + } + + protected: + void evalPhaseStorage_(const int phaseIdx) + { + if(useMoles) // mole-fraction formulation + { + // evaluate the storage terms of a single phase + for (int i=0; i < this->fvGeometry_().numScv; i++) { + PrimaryVariables &storage = this->storageTerm_[i]; + const ElementVolumeVariables &elemVolVars = this->curVolVars_(); + const VolumeVariables &volVars = elemVolVars[i]; + + // compute storage term of all components within all phases + storage = 0; + for (int compIdx = 0; compIdx < numComponents; ++compIdx) + { + int eqIdx = (compIdx == wCompIdx) ? contiWEqIdx : contiNEqIdx; + storage[eqIdx] += volVars.molarDensity(phaseIdx) + * volVars.saturation(phaseIdx) + * volVars.moleFraction(phaseIdx, compIdx); + } + + storage *= volVars.porosity(); + storage *= this->fvGeometry_().subContVol[i].volume; + } + } + else // mass-fraction formulation + { + // evaluate the storage terms of a single phase + for (int i=0; i < this->fvGeometry_().numScv; i++) { + PrimaryVariables &storage = this->storageTerm_[i]; + const ElementVolumeVariables &elemVolVars = this->curVolVars_(); + const VolumeVariables &volVars = elemVolVars[i]; + + // compute storage term of all components within all phases + storage = 0; + for (int compIdx = 0; compIdx < numComponents; ++compIdx) + { + int eqIdx = (compIdx == wCompIdx) ? contiWEqIdx : contiNEqIdx; + storage[eqIdx] += volVars.density(phaseIdx) + * volVars.saturation(phaseIdx) + * volVars.massFraction(phaseIdx, compIdx); + } + + storage *= volVars.porosity(); + storage *= this->fvGeometry_().subContVol[i].volume; + } + } + } + + /*! + * \brief Returns the equation index of the first mass-balance equation + * of the component (used for loops) + * + * Returns the equation index of the first mass-balance equation + * of the component (used for loops) if one component mass balance + * is replaced by the total mass balance, this is the index + * of the remaining component mass-balance equation. + */ + unsigned int contiCompIdx1_() const { + switch (replaceCompEqIdx) + { + case contiWEqIdx: return contiNEqIdx; + case contiNEqIdx: return contiWEqIdx; + default: return 0; + } + } + + /*! + * \brief Returns the equation index of the second mass balance + * of the component (used for loops) + * + * Returns the equation index of the second mass balance + * of the component (used for loops) + * if one component mass balance is replaced by the total mass balance + * (replaceCompEqIdx < 2), this index is the same as contiCompIdx1(). + */ + unsigned int contiCompIdx2_() const { + switch (replaceCompEqIdx) + { + case contiWEqIdx: return contiNEqIdx; + case contiNEqIdx: return contiWEqIdx; + default: return numComponents-1; + } + } + + Implementation *asImp_() + { return static_cast (this); } + const Implementation *asImp_() const + { return static_cast (this); } + + private: + Scalar massUpwindWeight_; + + // TODO: dumux-course-task + // add private member enableDiffusion_ +}; + +} // end namespace Dumux + +#endif diff --git a/tutorial/ex2/mymateriallaw.hh b/tutorial/ex2/mymateriallaw.hh new file mode 100644 index 0000000000..662ee49fa3 --- /dev/null +++ b/tutorial/ex2/mymateriallaw.hh @@ -0,0 +1,115 @@ +// -*- 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 Implementation of the capillary pressure and + * relative permeability <-> saturation relations. + * + */ +#ifndef DUMUX_MY_MATERIAL_LAW_HH +#define DUMUX_MY_MATERIAL_LAW_HH + +#include +#include + +namespace Dumux +{ +/*! + * \ingroup fluidmatrixinteractionslaws + * \note a simple material law using the BrooksCoreyParams + */ +template > +class MyMaterialLaw +{ +public: + typedef ParamsT Params; + typedef typename Params::Scalar Scalar; + + /*! + * \brief The capillary pressure-saturation curve + * \param swe saturation of the wetting phase \f$\mathrm{[\overline{S}_w]}\f$ + * \param params A container object that is populated with the appropriate coefficients for the respective law. + * Therefore, in the (problem specific) spatialParameters first, the material law is chosen, + and then the params container is constructed accordingly. Afterwards the values are set there, too. + * \return capillary pressure + * TODO: dumux-course-task + * Implement the pc(swe) function + */ + static Scalar pc(const Params ¶ms, Scalar swe) + { + return 0.0; + } + + /*! + * \brief The relative permeability for the wetting phase of + * the medium implied by the Brooks-Corey + * parameterization. + * + * \param swe The mobile saturation of the wetting phase. + * \param params A container object that is populated with the appropriate coefficients for the respective law. + * Therefore, in the (problem specific) spatialParameters first, the material law is chosen, + * and then the params container is constructed accordingly. Afterwards the values are set there, too. + * \return Relative permeability of the wetting phase calculated as implied by Brooks & Corey. + * + * \note Instead of undefined behaviour if pc is not in the valid range, we return a valid number, + * by clamping the input. + */ + static Scalar krw(const Params ¶ms, Scalar swe) + { + using std::pow; + using std::min; + using std::max; + + swe = min(max(swe, 0.0), 1.0); // the equation below is only defined for 0.0 <= swe <= 1.0 + + return pow(swe, 2.0/params.lambda() + 3); + } + + /*! + * \brief The relative permeability for the non-wetting phase of + * the medium as implied by the Brooks-Corey + * parameterization. + * + * \param swe The mobile saturation of the wetting phase. + * \param params A container object that is populated with the appropriate coefficients for the respective law. + * Therefore, in the (problem specific) spatialParameters first, the material law is chosen, and then the params container + * is constructed accordingly. Afterwards the values are set there, too. + * \return Relative permeability of the non-wetting phase calculated as implied by Brooks & Corey. + * + * \note Instead of undefined behaviour if pc is not in the valid range, we return a valid number, + * by clamping the input. + */ + static Scalar krn(const Params ¶ms, Scalar swe) + { + using std::pow; + using std::min; + using std::max; + + swe = min(max(swe, 0.0), 1.0); // the equation below is only defined for 0.0 <= swe <= 1.0 + + const Scalar exponent = 2.0/params.lambda() + 1; + const Scalar tmp = 1.0 - swe; + return tmp*tmp*(1.0 - pow(swe, exponent)); + } +}; + +} // end namespace Dumux + +#endif diff --git a/tutorial/solution/ex2/injection2p2cproblem.hh b/tutorial/solution/ex2/injection2p2cproblem.hh new file mode 100644 index 0000000000..716f530614 --- /dev/null +++ b/tutorial/solution/ex2/injection2p2cproblem.hh @@ -0,0 +1,318 @@ +// -*- 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 Problem where air is injected under a low permeable layer in a depth of 2700m. + */ +#ifndef DUMUX_INJECTION_2P2C_PROBLEM_HH +#define DUMUX_INJECTION_2P2C_PROBLEM_HH + +#include +#include +#include + +#include "injection2p2cspatialparams.hh" + +// TODO: dumux-course-task +// Include the local residual header +#include "mylocalresidual.hh" + +namespace Dumux +{ + +// foward declaration +template +class Injection2p2cProblem; + +// setup property TypeTag +namespace Properties +{ +// TODO: dumux-course-task +// inherit from MyLocalResidualParams +NEW_TYPE_TAG(Injection2p2cProblem, INHERITS_FROM(TwoPTwoC, InjectionSpatialParams, MyLocalResidualParams)); +NEW_TYPE_TAG(Injection2p2cBoxProblem, INHERITS_FROM(BoxModel, Injection2p2cProblem)); +NEW_TYPE_TAG(Injection2p2pcCCProblem, INHERITS_FROM(CCModel, Injection2p2cProblem)); + +// Set the grid type +SET_TYPE_PROP(Injection2p2cProblem, Grid, Dune::YaspGrid<2>); + +// Set the problem property +SET_TYPE_PROP(Injection2p2cProblem, Problem, Injection2p2cProblem); + +// TODO: dumux-course-task +// change the local residual type to MyTwoPTwoCLocalResidual +SET_TYPE_PROP(Injection2p2cProblem, LocalResidual, MyTwoPTwoCLocalResidual); + +// Set fluid configuration +SET_TYPE_PROP(Injection2p2cProblem, + FluidSystem, + FluidSystems::H2ON2); + +// Define whether mole(true) or mass (false) fractions are used +SET_BOOL_PROP(Injection2p2cProblem, UseMoles, true); + +} // end namespace Properties + +/*! + * \ingroup TwoPTwoCModel + * \ingroup ImplicitTestProblems + * \brief Problem where air is injected under a low permeable layer in a depth of 2700m. + * + * The domain is sized 60m times 40m and consists of two layers, a moderately + * permeable one (\f$ K=10e-12\f$) for \f$ y<22m\f$ and one with a lower permeablility (\f$ K=10e-13\f$) + * in the rest of the domain. + * + * Nitrogen is injected into a water-filled aquifer through a well. First, we inject for one month. + * Then, we continue simulating the development of the nitrogen plume for 10 years. + * This is realized with a Neumann boundary condition at the right boundary + * (\f$ 7m +class Injection2p2cProblem : public ImplicitPorousMediaProblem +{ + typedef ImplicitPorousMediaProblem ParentType; + + typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; + typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; + typedef typename GET_PROP_TYPE(TypeTag, FluidSystem) FluidSystem; + + // grid world dimension + static constexpr auto dimWorld = GridView::dimensionworld; + + typedef typename GET_PROP_TYPE(TypeTag, Indices) Indices; + typedef typename GET_PROP_TYPE(TypeTag, PrimaryVariables) PrimaryVariables; + typedef typename GET_PROP_TYPE(TypeTag, BoundaryTypes) BoundaryTypes; + typedef typename GET_PROP_TYPE(TypeTag, TimeManager) TimeManager; + typedef typename GET_PROP_TYPE(TypeTag, MaterialLaw) MaterialLaw; + typedef Dune::FieldVector GlobalPosition; + +public: + /*! + * \brief The constructor + * + * \param timeManager The time manager + * \param gridView The grid view + */ + Injection2p2cProblem(TimeManager &timeManager, const GridView &gridView) + : ParentType(timeManager, gridView) + { + // 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 + name_ = GET_RUNTIME_PARAM_FROM_GROUP(TypeTag, std::string, Problem, Name); + // depth of the aquifer, units: m + aquiferDepth_ = GET_RUNTIME_PARAM_FROM_GROUP(TypeTag, Scalar, Problem, AquiferDepth); + // inflow rate of nitrogen water vapor mixture, units: kg/(s m^2) + totalAreaSpecificInflow_ = GET_RUNTIME_PARAM_FROM_GROUP(TypeTag, Scalar, Problem, TotalAreaSpecificInflow); + // the duration of the injection, units: second + injectionDuration_ = GET_RUNTIME_PARAM_FROM_GROUP(TypeTag, Scalar, Problem, InjectionDuration); + } + + /*! + * \brief User defined output after the time integration + * + * Will be called diretly after the time integration + */ + void postTimeStep() + { + // Calculate storage terms + PrimaryVariables storageW, storageN; + this->model().globalPhaseStorage(storageW, Indices::wPhaseIdx); + this->model().globalPhaseStorage(storageN, Indices::nPhaseIdx); + + // Write mass balance information for rank 0 + if (this->gridView().comm().rank() == 0) + { + std::cout <<"Storage: wetting=[" << storageW << "]" + << " nonwetting=[" << storageN << "]" << std::endl; + } + } + + /*! + * \name Problem parameters + */ + // \{ + + /*! + * \brief Returns the problem name + * + * This is used as a prefix for files generated by the simulation. + */ + const std::string& name() const + { return name_; } + + /*! + * \brief Returns the temperature in \f$ K \f$ + */ + Scalar temperature() const + { return 273.15 + 30; } + + /*! + * \brief Returns the source term + * + * \param values Stores the source values for the conservation equations in + * \f$ [ \textnormal{unit of primary variable} / (m^\textrm{dim} \cdot s )] \f$ + * \param globalPos The global position + */ + void sourceAtPos(PrimaryVariables &values, + const GlobalPosition &globalPos) const + { values = 0; } + + // \} + + /*! + * \name Boundary conditions + */ + // \{ + + /*! + * \brief Specifies which kind of boundary condition should be + * used for which equation on a given boundary segment + * + * \param values Stores the value of the boundary type + * \param globalPos The global position + */ + void boundaryTypesAtPos(BoundaryTypes &values, + const GlobalPosition &globalPos) const + { + // Set Dirichlet at the bottom of the domain + if (globalPos[dimWorld-1] < eps_) + { + values.setAllDirichlet(); + } + + // and Neuman boundary conditions everywhere else + // note that we don't differentiate between Neumann and Robin boundary types + else + { + values.setAllNeumann(); + } + } + + /*! + * \brief Evaluates the boundary conditions for a Dirichlet + * boundary segment + * + * \param values Stores the Dirichlet values for the conservation equations in + * \f$ [ \textnormal{unit of primary variable} ] \f$ + * \param globalPos The global position + */ + void dirichletAtPos(PrimaryVariables &values, const GlobalPosition &globalPos) const + { initialAtPos(values, globalPos); } + + /*! + * \brief Evaluates the boundary conditions for a Neumann boundary segment. + * + * \param values Stores the Neumann values for the conservation equations in + * \f$ [ \textnormal{unit of conserved quantity} / (m^(dim-1) \cdot s )] \f$ + * \param globalPos The globalPosition of the boundary interface + */ + void neumannAtPos(PrimaryVariables &values, + const GlobalPosition &globalPos) const + { + // initialize values to zero, i.e. no-flow Neumann boundary conditions + values = 0; + + //if we are inside the injection zone set inflow Neumann boundary conditions + if (this->timeManager().time() + this->timeManager().timeStepSize() < injectionDuration_ + && globalPos[1] < 15 + eps_ && globalPos[1] > 7 - eps_ && globalPos[0] > 0.9*this->bBoxMax()[0]) + { + // set the Neumann values for the Nitrogen component balance + // convert from units kg/(s*m^2) to mole/(s*m^2) + values[Indices::contiNEqIdx] = -totalAreaSpecificInflow_/FluidSystem::molarMass(FluidSystem::nCompIdx); + values[Indices::contiWEqIdx] = 0.0; + } + } + + // \} + + /*! + * \name Volume terms + */ + // \{ + + /*! + * \brief Evaluates the initial values for a control volume + * + * \param values Stores the initial values for the conservation equations in + * \f$ [ \textnormal{unit of primary variables} ] \f$ + * \param globalPos The global position + */ + void initialAtPos(PrimaryVariables &values, const GlobalPosition &globalPos) const + { + // 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]); + + // initially we have some nitrogen dissolved + // saturation mole fraction would be + // moleFracLiquidN2 = (pw + pc + p_vap^sat)/henry; + const Scalar moleFracLiquidN2 = pw*0.95/BinaryCoeff::H2O_N2::henry(temperature()); + + // note that because we start with a single phase system the primary variables + // are pl and x^w_N2. This will switch as soon after we start injecting to a two + // phase system so the primary variables will be pl and Sn (non-wetting saturation). + values[Indices::switchIdx] = moleFracLiquidN2; + values[Indices::pressureIdx] = pw; + } + + /*! + * \brief Return the initial phase state inside a control volume. + * + * \param globalPos The global position + * \note we start with a single phase system + */ + int initialPhasePresenceAtPos(const GlobalPosition &globalPos) const + { return Indices::wPhaseOnly; } + + // \} + + //! If we should write restart files + bool shouldWriteRestartFile() const + { return false; } + +private: + static constexpr Scalar eps_ = 1e-6; + std::string name_; //! Problem name + Scalar aquiferDepth_; //! Depth of the aquifer in m + Scalar totalAreaSpecificInflow_; //! Area specific inflow rate in mole/(s*m^2) + Scalar injectionDuration_; //! Duration of the injection in seconds +}; + +} // end namespace Dumux + +#endif diff --git a/tutorial/ex2/injection2pspatialparams.hh b/tutorial/solution/ex2/injection2p2cspatialparams.hh similarity index 54% rename from tutorial/ex2/injection2pspatialparams.hh rename to tutorial/solution/ex2/injection2p2cspatialparams.hh index fc85aa4c21..de2eb15856 100644 --- a/tutorial/ex2/injection2pspatialparams.hh +++ b/tutorial/solution/ex2/injection2p2cspatialparams.hh @@ -30,16 +30,23 @@ #include #include #include +// TODO: dumux-course-task +// Inlcude your own material law +#include "mymateriallaw.hh" + +#include +#include #include namespace Dumux { -//forward declaration +// forward declaration template class InjectionSpatialParams; +// setup property TypeTag namespace Properties { // The spatial parameters TypeTag @@ -48,11 +55,17 @@ NEW_TYPE_TAG(InjectionSpatialParams); // Set the spatial parameters SET_TYPE_PROP(InjectionSpatialParams, SpatialParams, InjectionSpatialParams); +// TODO: dumux-course-task +// Use your own material law instead // Set the material law parameterized by absolute saturations -SET_TYPE_PROP(InjectionSpatialParams, - MaterialLaw, - EffToAbsLaw >); -} +SET_PROP(InjectionSpatialParams, MaterialLaw) +{ + using Scalar = typename GET_PROP_TYPE(TypeTag, Scalar); + // using type = EffToAbsLaw>; + using type = EffToAbsLaw>; +}; + +} // end namespace Properties /*! * \ingroup TwoPTwoCModel @@ -65,62 +78,59 @@ template class InjectionSpatialParams : public ImplicitSpatialParams { typedef ImplicitSpatialParams ParentType; - typedef typename GET_PROP_TYPE(TypeTag, Grid) Grid; typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; - typedef typename Grid::ctype CoordScalar; - typedef typename GET_PROP_TYPE(TypeTag, FluidSystem) FluidSystem; + typedef typename GridView::ctype CoordinateType; enum { dim=GridView::dimension, dimWorld=GridView::dimensionworld }; - typedef Dune::FieldVector GlobalPosition; - + typedef Dune::FieldVector GlobalPosition; typedef typename GET_PROP_TYPE(TypeTag, FVElementGeometry) FVElementGeometry; typedef typename GridView::template Codim<0>::Entity Element; - -public: typedef typename GET_PROP_TYPE(TypeTag, MaterialLaw) MaterialLaw; typedef typename MaterialLaw::Params MaterialLawParams; +public: + /*! * \brief The constructor * * \param gridView The grid view */ InjectionSpatialParams(const GridView &gridView) - : ParentType(gridView) + : ParentType(gridView) { - layerBottom_ = 25.0; + aquiferHeightFromBottom_ = 30.0; // intrinsic permeabilities - fineK_ = 1e-13; - coarseK_ = 1e-12; + aquitardK_ = GET_RUNTIME_PARAM(TypeTag, Scalar, SpatialParams.PermeabilityAquitard); + aquiferK_ = GET_RUNTIME_PARAM(TypeTag, Scalar, SpatialParams.PermeabilityAquifer); // porosities - finePorosity_ = 0.2; - coarsePorosity_ = 0.4; - - //materialLawParams - fineEntryPressure_ = GET_RUNTIME_PARAM(TypeTag, Scalar, SpatialParams.EntryPressureFine); - coarseEntryPressure_ = GET_RUNTIME_PARAM(TypeTag, Scalar, SpatialParams.EntryPressureCoarse); - - // heat conductivity of granite - lambdaSolid_ = 2.8; + aquitardPorosity_ = 0.2; + aquiferPorosity_ = 0.4; // residual saturations - fineMaterialParams_.setSwr(0.2); - fineMaterialParams_.setSnr(0.0); - coarseMaterialParams_.setSwr(0.2); - coarseMaterialParams_.setSnr(0.0); + aquitardMaterialParams_.setSwr(0.2); + aquitardMaterialParams_.setSnr(0.0); + aquiferMaterialParams_.setSwr(0.2); + aquiferMaterialParams_.setSnr(0.0); // parameters for the Brooks-Corey law - fineMaterialParams_.setPe(fineEntryPressure_); - coarseMaterialParams_.setPe(coarseEntryPressure_); - fineMaterialParams_.setLambda(2.0); - coarseMaterialParams_.setLambda(2.0); + aquitardMaterialParams_.setPe(GET_RUNTIME_PARAM(TypeTag, Scalar, SpatialParams.EntryPressureAquitard)); + aquiferMaterialParams_.setPe(GET_RUNTIME_PARAM(TypeTag, Scalar, SpatialParams.EntryPressureAquifer)); + aquitardMaterialParams_.setLambda(2.0); + aquiferMaterialParams_.setLambda(2.0); + + // plot the material laws using gnuplot and exit + if (GET_RUNTIME_PARAM(TypeTag, bool, Problem.OnlyPlotMaterialLaws)) + { + plotMaterialLaws(); + exit(0); + } } /*! @@ -130,14 +140,14 @@ public: * \param fvGeometry The finite volume geometry of the element * \param scvIdx The local index of the sub-control volume */ - const Scalar intrinsicPermeability(const Element &element, - const FVElementGeometry &fvGeometry, - const int scvIdx) const + Scalar intrinsicPermeability(const Element &element, + const FVElementGeometry &fvGeometry, + const int scvIdx) const { const GlobalPosition &globalPos = fvGeometry.subContVol[scvIdx].global; - if (isFineMaterial_(globalPos)) - return fineK_; - return coarseK_; + if (isInAquitard_(globalPos)) + return aquitardK_; + return aquiferK_; } /*! @@ -152,9 +162,9 @@ public: const int scvIdx) const { const GlobalPosition &globalPos = fvGeometry.subContVol[scvIdx].global; - if (isFineMaterial_(globalPos)) - return finePorosity_; - return coarsePorosity_; + if (isInAquitard_(globalPos)) + return aquitardPorosity_; + return aquiferPorosity_; } @@ -171,83 +181,43 @@ public: const int scvIdx) const { const GlobalPosition &globalPos = fvGeometry.subContVol[scvIdx].global; - if (isFineMaterial_(globalPos)) - return fineMaterialParams_; - return coarseMaterialParams_; + if (isInAquitard_(globalPos)) + return aquitardMaterialParams_; + return aquiferMaterialParams_; } /*! - * These parameters are only needed for nonisothermal models. Comment them in if you want to implement the 2pni model. - */ - - /*! - * \brief Returns the heat capacity \f$[J / (kg K)]\f$ of the rock matrix. - * - * This is only required for non-isothermal models. - * - * \param element The finite element - * \param fvGeometry The finite volume geometry - * \param scvIdx The local index of the sub-control volume + * \brief Creates a gnuplot output of the pc-Sw curve */ -// Scalar solidHeatCapacity(const Element &element, -// const FVElementGeometry &fvGeometry, -// const int scvIdx) const -// { -// return 790; // specific heat capacity of granite [J / (kg K)] -// } - - /*! - * \brief Returns the mass density \f$[kg / m^3]\f$ of the rock matrix. - * - * This is only required for non-isothermal models. - * - * \param element The finite element - * \param fvGeometry The finite volume geometry - * \param scvIdx The local index of the sub-control volume - */ -// Scalar solidDensity(const Element &element, -// const FVElementGeometry &fvGeometry, -// const int scvIdx) const -// { -// return 2700; // density of granite [kg/m^3] -// } - - /*! - * \brief Returns the thermal conductivity \f$\mathrm{[W/(m K)]}\f$ of the solid - * - * This is only required for non-isothermal models. - * - * \param element The finite element - * \param fvGeometry The finite volume geometry of the element - * \param scvIdx The local index of the sub-control volume - */ -// Scalar solidThermalConductivity(const Element &element, -// const FVElementGeometry &fvGeometry, -// const int scvIdx) const -// { -// return lambdaSolid_; -// } + void plotMaterialLaws() + { + PlotMaterialLaw plotMaterialLaw; + GnuplotInterface gnuplot; + plotMaterialLaw.addpcswcurve(gnuplot, aquitardMaterialParams_, 0.2, 1.0, "upper layer (fine, aquitard)", "w lp"); + plotMaterialLaw.addpcswcurve(gnuplot, aquiferMaterialParams_, 0.2, 1.0, "lower layer (coarse, aquifer)", "w l"); + gnuplot.setOption("set xrange [0:1]"); + gnuplot.setOption("set label \"residual\\nsaturation\" at 0.1,100000 center"); + gnuplot.plot("pc-Sw"); + } private: - bool isFineMaterial_(const GlobalPosition &globalPos) const - { return globalPos[dimWorld-1] > layerBottom_; } - Scalar fineK_; - Scalar coarseK_; - Scalar layerBottom_; + static constexpr Scalar eps_ = 1e-6; - Scalar finePorosity_; - Scalar coarsePorosity_; + bool isInAquitard_(const GlobalPosition &globalPos) const + { return globalPos[dimWorld-1] > aquiferHeightFromBottom_ + eps_; } - Scalar lambdaSolid_; + Scalar aquitardK_; + Scalar aquiferK_; + Scalar aquiferHeightFromBottom_; - Scalar fineEntryPressure_; - Scalar coarseEntryPressure_; + Scalar aquitardPorosity_; + Scalar aquiferPorosity_; - MaterialLawParams fineMaterialParams_; - MaterialLawParams coarseMaterialParams_; + MaterialLawParams aquitardMaterialParams_; + MaterialLawParams aquiferMaterialParams_; }; -} +} // end namespace Dumux #endif diff --git a/tutorial/solution/ex2/mylocalresidual.hh b/tutorial/solution/ex2/mylocalresidual.hh new file mode 100644 index 0000000000..8995eb80d5 --- /dev/null +++ b/tutorial/solution/ex2/mylocalresidual.hh @@ -0,0 +1,545 @@ +// -*- 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 Element-wise calculation of the Jacobian matrix for problems + * using the two-phase two-component fully implicit model. + */ + +#ifndef DUMUX_MY_2P2C_LOCAL_RESIDUAL_HH +#define DUMUX_MY_2P2C_LOCAL_RESIDUAL_HH + +#include + +namespace Dumux +{ + +// TODO: dumux-course-task +// implement new TypeTag MyLocalResidualParams +namespace Properties +{ +NEW_TYPE_TAG(MyLocalResidualParams); +NEW_PROP_TAG(ProblemEnableDiffusion); +SET_BOOL_PROP(MyLocalResidualParams, ProblemEnableDiffusion, true); +} // end namespace Properties + +/*! + * \ingroup TwoPTwoCModel + * \ingroup ImplicitLocalResidual + * \brief Element-wise calculation of the Jacobian matrix for problems + * using the two-phase two-component fully implicit model. + * + * This class is used to fill the gaps in ImplicitLocalResidual for the + * two-phase two-component flow. + */ +template +class MyTwoPTwoCLocalResidual: public GET_PROP_TYPE(TypeTag, BaseLocalResidual) +{ + protected: + typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; + typedef typename GET_PROP_TYPE(TypeTag, LocalResidual) Implementation; + typedef typename GET_PROP_TYPE(TypeTag, FluidSystem) FluidSystem; + typedef typename GET_PROP_TYPE(TypeTag, PrimaryVariables) PrimaryVariables; + typedef typename GET_PROP_TYPE(TypeTag, FVElementGeometry) FVElementGeometry; + typedef typename GET_PROP_TYPE(TypeTag, VolumeVariables) VolumeVariables; + typedef typename GET_PROP_TYPE(TypeTag, ElementVolumeVariables) ElementVolumeVariables; + typedef typename GET_PROP_TYPE(TypeTag, ElementBoundaryTypes) ElementBoundaryTypes; + typedef typename GET_PROP_TYPE(TypeTag, FluxVariables) FluxVariables; + enum + { + numPhases = GET_PROP_VALUE(TypeTag, NumPhases), + numComponents = GET_PROP_VALUE(TypeTag, NumComponents) + }; + + typedef typename GET_PROP_TYPE(TypeTag, Indices) Indices; + enum + { + contiWEqIdx = Indices::contiWEqIdx, + contiNEqIdx = Indices::contiNEqIdx, + wPhaseIdx = Indices::wPhaseIdx, + nPhaseIdx = Indices::nPhaseIdx, + wCompIdx = Indices::wCompIdx, + nCompIdx = Indices::nCompIdx + }; + + typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; + typedef typename GridView::template Codim<0>::Entity Element; + + static constexpr unsigned int replaceCompEqIdx = GET_PROP_VALUE(TypeTag, ReplaceCompEqIdx); + + //! Property that defines whether mole or mass fractions are used + static const bool useMoles = GET_PROP_VALUE(TypeTag, UseMoles); + + public: + /*! + * \brief Constructor + * + * Sets the mass upwind weight. + */ + MyTwoPTwoCLocalResidual() + { + // retrieve the upwind weight for the mass conservation equations. Use the value + // specified via the property system as default, and overwrite + // it by the run-time parameter from the Dune::ParameterTree + massUpwindWeight_ = GET_PARAM_FROM_GROUP(TypeTag, Scalar, Implicit, MassUpwindWeight); + + // TODO: dumux-course-task + // get parameter Problem.EnableDiffusion + enableDiffusion_ = GET_PARAM_FROM_GROUP(TypeTag, bool, Problem, EnableDiffusion); + } + + /*! + * \brief Evaluate the storage term of the current solution in a + * single phase. + * + * \param element The element + * \param phaseIdx The index of the fluid phase + */ + void evalPhaseStorage(const Element &element, const int phaseIdx) + { + FVElementGeometry fvGeometry; + fvGeometry.update(this->gridView_(), element); + ElementBoundaryTypes bcTypes; + bcTypes.update(this->problem_(), element, fvGeometry); + ElementVolumeVariables elemVolVars; + elemVolVars.update(this->problem_(), element, fvGeometry, false); + + this->storageTerm_.resize(fvGeometry.numScv); + this->storageTerm_ = 0; + + this->elemPtr_ = &element; + this->fvElemGeomPtr_ = &fvGeometry; + this->bcTypesPtr_ = &bcTypes; + this->prevVolVarsPtr_ = 0; + this->curVolVarsPtr_ = &elemVolVars; + evalPhaseStorage_(phaseIdx); + } + + /*! + * \brief Evaluate the amount of all conservation quantities + * (e.g. phase mass) within a sub-control volume. + * + * \param storage The mass of the component within the sub-control volume + * \param scvIdx The sub-control-volume index + * \param usePrevSol Based on usePrevSol solution of current or previous time step is used + * + * The result should be averaged over the volume (e.g. phase mass + * inside a sub-control volume divided by the volume) + */ + void computeStorage(PrimaryVariables &storage, const int scvIdx, bool usePrevSol) const + { + // if flag usePrevSol is set, the solution from the previous + // time step is used, otherwise the current solution is + // used. The secondary variables are used accordingly. This + // is required to compute the derivative of the storage term + // using the implicit Euler method. + const ElementVolumeVariables &elemVolVars = usePrevSol ? this->prevVolVars_() + : this->curVolVars_(); + const VolumeVariables &volVars = elemVolVars[scvIdx]; + + // compute storage term of all components within all phases + storage = 0; + if(useMoles) // mole-fraction formulation + { + for (unsigned int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) + { + for (unsigned int compIdx = contiCompIdx1_(); compIdx <= contiCompIdx2_(); ++compIdx) + { + unsigned int eqIdx = (compIdx == wCompIdx) ? contiWEqIdx : contiNEqIdx; + storage[eqIdx] += volVars.molarDensity(phaseIdx) + * volVars.saturation(phaseIdx) + * volVars.moleFraction(phaseIdx, compIdx); + } + // this is only processed if one component mass balance equation + // is replaced by the total mass balance equation + if (replaceCompEqIdx < numComponents) + storage[replaceCompEqIdx] += + volVars.molarDensity(phaseIdx) + * volVars.saturation(phaseIdx); + } + storage *= volVars.porosity(); + } + else // mass-fraction formulation + { + for (unsigned int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) + { + for (unsigned int compIdx = contiCompIdx1_(); compIdx <= contiCompIdx2_(); ++compIdx) + { + unsigned int eqIdx = (compIdx == wCompIdx) ? contiWEqIdx : contiNEqIdx; + storage[eqIdx] += volVars.density(phaseIdx) + * volVars.saturation(phaseIdx) + * volVars.massFraction(phaseIdx, compIdx); + } + // this is only processed if one component mass balance equation + // is replaced by the total mass balance equation + if (replaceCompEqIdx < numComponents) + storage[replaceCompEqIdx] += + volVars.density(phaseIdx) + * volVars.saturation(phaseIdx); + } + storage *= volVars.porosity(); + } + } + + /*! + * \brief Evaluates the total flux of all conservation quantities + * over a face of a sub-control volume. + * + * \param flux The flux over the sub-control-volume face for each component + * \param fIdx The index of the sub-control-volume face + * \param onBoundary Evaluate flux at inner sub-control-volume face or on a boundary face + */ + void computeFlux(PrimaryVariables &flux, const int fIdx, bool onBoundary=false) const + { + // update the flux variables + FluxVariables fluxVars; + fluxVars.update(this->problem_(), + this->element_(), + this->fvGeometry_(), + fIdx, + this->curVolVars_(), + onBoundary); + + flux = 0; + + // add advective fluxes + computeAdvectiveFlux(flux, fluxVars); + + // add diffusive fluxes + // TODO: dumux-course-task + // only add diffusive fluxes if diffusion is enabled + if (enableDiffusion_) + computeDiffusiveFlux(flux, fluxVars); + } + + /*! + * \brief Evaluates the advective mass flux of all components over + * a face of a sub-control volume. + * + * \param flux The flux over the sub-control-volume face for each component + * \param fluxVars The flux variables at the current sub-control-volume face + */ + void computeAdvectiveFlux(PrimaryVariables &flux, const FluxVariables &fluxVars) const + { + //////// + // advective fluxes of all components in all phases + //////// + + if(useMoles) // mole-fraction formulation + { + for (unsigned int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) + { + // data attached to upstream and the downstream vertices + // of the current phase + const VolumeVariables &up = + this->curVolVars_(fluxVars.upstreamIdx(phaseIdx)); + const VolumeVariables &dn = + this->curVolVars_(fluxVars.downstreamIdx(phaseIdx)); + + for (unsigned int compIdx = contiCompIdx1_(); compIdx <= contiCompIdx2_(); ++compIdx) + { + unsigned int eqIdx = (compIdx == wCompIdx) ? contiWEqIdx : contiNEqIdx; + // add advective flux of current component in current + // phase + if (massUpwindWeight_ > 0.0) + // upstream vertex + flux[eqIdx] += + fluxVars.volumeFlux(phaseIdx) + * massUpwindWeight_ + * up.molarDensity(phaseIdx) + * up.moleFraction(phaseIdx, compIdx); + if (massUpwindWeight_ < 1.0) + // downstream vertex + flux[eqIdx] += + fluxVars.volumeFlux(phaseIdx) + * (1 - massUpwindWeight_) + * dn.molarDensity(phaseIdx) + * dn.moleFraction(phaseIdx, compIdx); + + Valgrind::CheckDefined(fluxVars.volumeFlux(phaseIdx)); + Valgrind::CheckDefined(up.molarDensity(phaseIdx)); + Valgrind::CheckDefined(up.moleFraction(phaseIdx, compIdx)); + Valgrind::CheckDefined(dn.molarDensity(phaseIdx)); + Valgrind::CheckDefined(dn.moleFraction(phaseIdx, compIdx)); + } + // flux of the total mass balance; + // this is only processed if one component mass balance equation + // is replaced by a total mass balance equation + if (replaceCompEqIdx < numComponents) + { + // upstream vertex + if (massUpwindWeight_ > 0.0) + flux[replaceCompEqIdx] += + fluxVars.volumeFlux(phaseIdx) + * massUpwindWeight_ + * up.molarDensity(phaseIdx); + // downstream vertex + if (massUpwindWeight_ < 1.0) + flux[replaceCompEqIdx] += + fluxVars.volumeFlux(phaseIdx) + * (1 - massUpwindWeight_) + * dn.molarDensity(phaseIdx); + Valgrind::CheckDefined(fluxVars.volumeFlux(phaseIdx)); + Valgrind::CheckDefined(up.molarDensity(phaseIdx)); + Valgrind::CheckDefined(dn.molarDensity(phaseIdx)); + + } + + } + } + else // mass-fraction formulation + { + for (unsigned int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) + { + // data attached to upstream and downstream vertices + // of the current phase + const VolumeVariables &up = + this->curVolVars_(fluxVars.upstreamIdx(phaseIdx)); + const VolumeVariables &dn = + this->curVolVars_(fluxVars.downstreamIdx(phaseIdx)); + + for (unsigned int compIdx = contiCompIdx1_(); compIdx <= contiCompIdx2_(); ++compIdx) + { + unsigned int eqIdx = (compIdx == wCompIdx) ? contiWEqIdx : contiNEqIdx; + // add advective flux of current component in current + // phase + if (massUpwindWeight_ > 0.0) + // upstream vertex + flux[eqIdx] += + fluxVars.volumeFlux(phaseIdx) + * massUpwindWeight_ + * up.density(phaseIdx) + * up.massFraction(phaseIdx, compIdx); + if (massUpwindWeight_ < 1.0) + // downstream vertex + flux[eqIdx] += + fluxVars.volumeFlux(phaseIdx) + * (1 - massUpwindWeight_) + * dn.density(phaseIdx) + * dn.massFraction(phaseIdx, compIdx); + + Valgrind::CheckDefined(fluxVars.volumeFlux(phaseIdx)); + Valgrind::CheckDefined(up.density(phaseIdx)); + Valgrind::CheckDefined(up.massFraction(phaseIdx, compIdx)); + Valgrind::CheckDefined(dn.density(phaseIdx)); + Valgrind::CheckDefined(dn.massFraction(phaseIdx, compIdx)); + } + // flux of the total mass balance; + // this is only processed if one component mass balance equation + // is replaced by a total mass balance equation + if (replaceCompEqIdx < numComponents) + { + // upstream vertex + if (massUpwindWeight_ > 0.0) + flux[replaceCompEqIdx] += + fluxVars.volumeFlux(phaseIdx) + * massUpwindWeight_ + * up.density(phaseIdx); + // downstream vertex + if (massUpwindWeight_ < 1.0) + flux[replaceCompEqIdx] += + fluxVars.volumeFlux(phaseIdx) + * (1 - massUpwindWeight_) + * dn.density(phaseIdx); + Valgrind::CheckDefined(fluxVars.volumeFlux(phaseIdx)); + Valgrind::CheckDefined(up.density(phaseIdx)); + Valgrind::CheckDefined(dn.density(phaseIdx)); + + } + + } + } + } + + /*! + * \brief Evaluates the diffusive mass flux of all components over + * a face of a sub-control volume. + * + * \param flux The flux over the sub-control-volume face for each component + * \param fluxVars The flux variables at the current sub-control-volume face + */ + void computeDiffusiveFlux(PrimaryVariables &flux, const FluxVariables &fluxVars) const + + { + if(useMoles) // mole-fraction formulation + { + // add diffusive flux of gas component in liquid phase + Scalar tmp = -(fluxVars.moleFractionGrad(wPhaseIdx)*fluxVars.face().normal) + * fluxVars.porousDiffCoeff(wPhaseIdx) + * fluxVars.molarDensity(wPhaseIdx); + // add the diffusive fluxes only to the component mass balance + if (replaceCompEqIdx != contiNEqIdx) + flux[contiNEqIdx] += tmp; + if (replaceCompEqIdx != contiWEqIdx) + flux[contiWEqIdx] -= tmp; + + // add diffusive flux of liquid component in non-wetting phase + tmp = -(fluxVars.moleFractionGrad(nPhaseIdx)*fluxVars.face().normal) + * fluxVars.porousDiffCoeff(nPhaseIdx) + * fluxVars.molarDensity(nPhaseIdx); + // add the diffusive fluxes only to the component mass balance + if (replaceCompEqIdx != contiWEqIdx) + flux[contiWEqIdx] += tmp; + if (replaceCompEqIdx != contiNEqIdx) + flux[contiNEqIdx] -= tmp; + } + else // mass-fraction formulation + { + // add diffusive flux of gas component in wetting phase + Scalar tmp = -(fluxVars.moleFractionGrad(wPhaseIdx)*fluxVars.face().normal) + * fluxVars.porousDiffCoeff(wPhaseIdx) + * fluxVars.molarDensity(wPhaseIdx); + // add the diffusive fluxes to the component mass balance and total mass balance + if (replaceCompEqIdx < numComponents) + { + flux[replaceCompEqIdx] += tmp * FluidSystem::molarMass(nCompIdx); + flux[replaceCompEqIdx] -= tmp * FluidSystem::molarMass(wCompIdx); + } + if (replaceCompEqIdx != contiWEqIdx) + { + flux[contiWEqIdx] -= tmp * FluidSystem::molarMass(wCompIdx); + } + if (replaceCompEqIdx != contiNEqIdx) + { + flux[contiNEqIdx] += tmp * FluidSystem::molarMass(nCompIdx); + } + + // add diffusive fluxes of liquid component in non-wetting phase + tmp = -(fluxVars.moleFractionGrad(nPhaseIdx)*fluxVars.face().normal) + * fluxVars.porousDiffCoeff(nPhaseIdx) + * fluxVars.molarDensity(nPhaseIdx); + // add the diffusive fluxes to the component mass balance and total mass balance + if (replaceCompEqIdx < numComponents) + { + flux[replaceCompEqIdx] += tmp * FluidSystem::molarMass(wCompIdx); + flux[replaceCompEqIdx] -= tmp * FluidSystem::molarMass(nCompIdx); + } + if (replaceCompEqIdx != contiWEqIdx) + { + flux[contiWEqIdx] += tmp * FluidSystem::molarMass(wCompIdx); + } + if (replaceCompEqIdx != contiNEqIdx) + { + flux[contiNEqIdx] -= tmp * FluidSystem::molarMass(nCompIdx); + } + } + } + + protected: + void evalPhaseStorage_(const int phaseIdx) + { + if(useMoles) // mole-fraction formulation + { + // evaluate the storage terms of a single phase + for (int i=0; i < this->fvGeometry_().numScv; i++) { + PrimaryVariables &storage = this->storageTerm_[i]; + const ElementVolumeVariables &elemVolVars = this->curVolVars_(); + const VolumeVariables &volVars = elemVolVars[i]; + + // compute storage term of all components within all phases + storage = 0; + for (int compIdx = 0; compIdx < numComponents; ++compIdx) + { + int eqIdx = (compIdx == wCompIdx) ? contiWEqIdx : contiNEqIdx; + storage[eqIdx] += volVars.molarDensity(phaseIdx) + * volVars.saturation(phaseIdx) + * volVars.moleFraction(phaseIdx, compIdx); + } + + storage *= volVars.porosity(); + storage *= this->fvGeometry_().subContVol[i].volume; + } + } + else // mass-fraction formulation + { + // evaluate the storage terms of a single phase + for (int i=0; i < this->fvGeometry_().numScv; i++) { + PrimaryVariables &storage = this->storageTerm_[i]; + const ElementVolumeVariables &elemVolVars = this->curVolVars_(); + const VolumeVariables &volVars = elemVolVars[i]; + + // compute storage term of all components within all phases + storage = 0; + for (int compIdx = 0; compIdx < numComponents; ++compIdx) + { + int eqIdx = (compIdx == wCompIdx) ? contiWEqIdx : contiNEqIdx; + storage[eqIdx] += volVars.density(phaseIdx) + * volVars.saturation(phaseIdx) + * volVars.massFraction(phaseIdx, compIdx); + } + + storage *= volVars.porosity(); + storage *= this->fvGeometry_().subContVol[i].volume; + } + } + } + + /*! + * \brief Returns the equation index of the first mass-balance equation + * of the component (used for loops) + * + * Returns the equation index of the first mass-balance equation + * of the component (used for loops) if one component mass balance + * is replaced by the total mass balance, this is the index + * of the remaining component mass-balance equation. + */ + unsigned int contiCompIdx1_() const { + switch (replaceCompEqIdx) + { + case contiWEqIdx: return contiNEqIdx; + case contiNEqIdx: return contiWEqIdx; + default: return 0; + } + } + + /*! + * \brief Returns the equation index of the second mass balance + * of the component (used for loops) + * + * Returns the equation index of the second mass balance + * of the component (used for loops) + * if one component mass balance is replaced by the total mass balance + * (replaceCompEqIdx < 2), this index is the same as contiCompIdx1(). + */ + unsigned int contiCompIdx2_() const { + switch (replaceCompEqIdx) + { + case contiWEqIdx: return contiNEqIdx; + case contiNEqIdx: return contiWEqIdx; + default: return numComponents-1; + } + } + + Implementation *asImp_() + { return static_cast (this); } + const Implementation *asImp_() const + { return static_cast (this); } + + private: + Scalar massUpwindWeight_; + + // TODO: dumux-course-task + // add private member enableDiffusion_ + bool enableDiffusion_; +}; + +} // end namespace Dumux + +#endif diff --git a/tutorial/solution/ex2/mymateriallaw.hh b/tutorial/solution/ex2/mymateriallaw.hh new file mode 100644 index 0000000000..dbd58c8ff9 --- /dev/null +++ b/tutorial/solution/ex2/mymateriallaw.hh @@ -0,0 +1,115 @@ +// -*- 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 Implementation of the capillary pressure and + * relative permeability <-> saturation relations. + * + */ +#ifndef DUMUX_MY_MATERIAL_LAW_HH +#define DUMUX_MY_MATERIAL_LAW_HH + +#include +#include + +namespace Dumux +{ +/*! + * \ingroup fluidmatrixinteractionslaws + * \note a simple material law using the BrooksCoreyParams + */ +template > +class MyMaterialLaw +{ +public: + typedef ParamsT Params; + typedef typename Params::Scalar Scalar; + + /*! + * \brief The capillary pressure-saturation curve + * \param swe saturation of the wetting phase \f$\mathrm{[\overline{S}_w]}\f$ + * \param params A container object that is populated with the appropriate coefficients for the respective law. + * Therefore, in the (problem specific) spatialParameters first, the material law is chosen, + and then the params container is constructed accordingly. Afterwards the values are set there, too. + * \return capillary pressure + * TODO: dumux-course-task + * Implement the pc(swe) function + */ + static Scalar pc(const Params ¶ms, Scalar swe) + { + return 1.0e5*(1.0-swe) + params.pe(); + } + + /*! + * \brief The relative permeability for the wetting phase of + * the medium implied by the Brooks-Corey + * parameterization. + * + * \param swe The mobile saturation of the wetting phase. + * \param params A container object that is populated with the appropriate coefficients for the respective law. + * Therefore, in the (problem specific) spatialParameters first, the material law is chosen, + * and then the params container is constructed accordingly. Afterwards the values are set there, too. + * \return Relative permeability of the wetting phase calculated as implied by Brooks & Corey. + * + * \note Instead of undefined behaviour if pc is not in the valid range, we return a valid number, + * by clamping the input. + */ + static Scalar krw(const Params ¶ms, Scalar swe) + { + using std::pow; + using std::min; + using std::max; + + swe = min(max(swe, 0.0), 1.0); // the equation below is only defined for 0.0 <= swe <= 1.0 + + return pow(swe, 2.0/params.lambda() + 3); + } + + /*! + * \brief The relative permeability for the non-wetting phase of + * the medium as implied by the Brooks-Corey + * parameterization. + * + * \param swe The mobile saturation of the wetting phase. + * \param params A container object that is populated with the appropriate coefficients for the respective law. + * Therefore, in the (problem specific) spatialParameters first, the material law is chosen, and then the params container + * is constructed accordingly. Afterwards the values are set there, too. + * \return Relative permeability of the non-wetting phase calculated as implied by Brooks & Corey. + * + * \note Instead of undefined behaviour if pc is not in the valid range, we return a valid number, + * by clamping the input. + */ + static Scalar krn(const Params ¶ms, Scalar swe) + { + using std::pow; + using std::min; + using std::max; + + swe = min(max(swe, 0.0), 1.0); // the equation below is only defined for 0.0 <= swe <= 1.0 + + const Scalar exponent = 2.0/params.lambda() + 1; + const Scalar tmp = 1.0 - swe; + return tmp*tmp*(1.0 - pow(swe, exponent)); + } +}; + +} // end namespace Dumux + +#endif -- GitLab From 44bb962b5fc577a6ba4fdf67e87d5ea2a6f7e875 Mon Sep 17 00:00:00 2001 From: Timo Koch Date: Thu, 21 Sep 2017 20:05:37 +0200 Subject: [PATCH 29/42] Update README.md ex2 --- tutorial/ex2/README.md | 42 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 39 insertions(+), 3 deletions(-) diff --git a/tutorial/ex2/README.md b/tutorial/ex2/README.md index 3b5f269c88..996f741ec3 100644 --- a/tutorial/ex2/README.md +++ b/tutorial/ex2/README.md @@ -61,7 +61,13 @@ DuMuX uses the term _material law_ to describe the law used to compute The file `mymateriallaw.hh` contains a custom implementation of such a material law. -* Implement the method `Scalar pc(Scalar sw)` by implementing your own capillary pressure relationship, e.g. a simple linear relationship $`p_C(S_w) = 1\cdot 10^5 \cdot (1-S_w)`$. +* Implement the method `Scalar pc(Scalar sw)` by implementing your own capillary pressure relationship, e.g. a simple linear relationship $`p_C(S_w) = 1\cdot 10^5 \cdot (1-S_w) + p_e`$. + +Note: `MyMaterialLaw` uses the `BrooksCoreyParams` class as parameter input. You can get the entry pressure that is set in the spatial params as follows + +```c++ +const auto pe = params.pe(); +``` The type (i.e. C++ type) of the material law is set in the file `injection2pspatialparams.hh` by using the DuMuX property system @@ -75,10 +81,38 @@ SET_PROP(InjectionSpatialParams, MaterialLaw) * Make DuMuX use your own material law by including the header `mymateriallaw.hh` and changing the alias `type`. This will make sure that your material law is used everywhere else in the code. +Note: Also use the wrapper class `EffToAbsLaw`. It takes care of converting absolute to effective saturations considering residual saturations. `MyMaterialLaw` +as other material laws (like Brooks-Corey, VanGenuchten, ...) in DuMuX only deals with effective saturations. + Verify your changes by recompiling and running the program. You should see a plot of your new function. +For the next task disable the plotting feature by changing the settings in the input file `exercise2.input` + +```ini +[Problem] +OnlyPlotMaterialLaws = false +``` + +


+### Task 4: Enable/Disable Gravity -> DuMuX parameters +
+ +DuMuX has many parameters that have default values. For example, per default all simulation consider gravity effects. +You can disable gravity for a study, simply by setting the parameter in the input file + +```ini +[Problem] +EnableGravity = false +``` + +Run the simulation with and without gravity. Change the `Problem.Name` parameter to create output files with different +names. Compare the results using paraview. You should immediately see the difference. + +A list of parameters that can be set through the input file are given [here](http://www.dumux.org/doxygen-stable/html-2.11/a06387.php). + +


-### Task 4: Implement your own local residual +### Task 5: Implement your own local residual
Most types in DuMuX are properties that can be changed just like the material law. In the following task we implement our own 2p2c local residual, i.e. the class that computes the element residual in every Newton step. The file `mylocalresidual.hh` contains a copy of the original local residual class used for the 2p2c model renamed to `template class MyTwoPTwoCLocalResidual`. @@ -159,4 +193,6 @@ You can now enable and disable diffusion through the input file EnableDiffusion = true / false ``` -Verify the difference at the non-wetting saturation front with and without diffusion. +Verify the difference in the parameter $`x_w^{N2}`$, i.e. the mole fraction of nitrogen in the +water phase, with and without diffusion. Note that due to diffusion being a slow process you +can only see the difference in later times. -- GitLab From 59a82755de25021beccb62cee8e816544256b061 Mon Sep 17 00:00:00 2001 From: Timo Koch Date: Thu, 21 Sep 2017 20:25:22 +0200 Subject: [PATCH 30/42] Update README.md ex 4 --- tutorial/ex4/README.md | 86 +++++++++++++++++++++++++++++++++--------- 1 file changed, 68 insertions(+), 18 deletions(-) diff --git a/tutorial/ex4/README.md b/tutorial/ex4/README.md index 2832c96cbc..de195573c2 100644 --- a/tutorial/ex4/README.md +++ b/tutorial/ex4/README.md @@ -1,42 +1,92 @@ # Exercise #4 (DuMuX course) This exercise describes how to create a new DuMuX module -and how to create a corresponding gitlab project. +and how to create a corresponding GitLab project. -## Create new DuMuX module +This is the suggested +workflow to develop code on top of DuMuX. + +### Task 1: Create new dune module +
+ +* Execute the following command (bash environment) in the top-folder, i.e. above the dumux folder -### 1. Execute the following command (bash environment): ```bash -$ ./dune-common/bin/duneproject +./dune-common/bin/duneproject ``` -Follow the introductions and specify -* Name of your module, e.g. dumux-ex -* Module dependency, which is dumux -### 2. Run dunecontrol -here you can use `--only=Module-Name` +* Follow the introductions and specify + * as name of the new module: `dumux-example` + * as module dependencies: `dumux` + * a version at your choice + * your email adress + +


+### Task 2: Rerun dunecontrol to configure your new project +
+The following command will configure your new module -## Create a new test case within your new DuMuX module +```bash +./dune-common/bin/dunecontrol --opts= --only=dumux-example all +``` -* Create a new folder (in your module folder), e.g. appl +


+### Task 3: Create a new test case within your new DuMuX module +
+ +* Create a new folder (in your module folder), e.g. `appl` + +```bash +mkdir appl +``` * Copy some test case from the dumux module, e.g. test_box1p + * Copy the problem, spatialparams, cc source file, input file -* Incorporate this test case into your cmake files +* Adjust the CMakeLists.txt file to include your new subdirectory -* Re-run **dunecontrol** +* Add a new CMakeLists.txt in the folder `appl` with the content -* Execute your test problem +```cmake +// add a new box 1p test +dune_add_test(NAME test_box1p + SOURCES test_box1p.cc) + +// link the input file to the build folder +dune_symlink_to_source_files(FILES test_box1p.input) + +``` + +* Reconfigure your module by running in the topmost directory of your new module + +```bash +cmake build-cmake +``` + +* Build and execute the test problem + +```bash +cd build-cmake +make build_tests +cd appl +./test_box1p +``` +


+### Task 4: Create a new gitlab project +
-## Create a new gitlab project +* Login with your username and password at https://git.iws.uni-stuttgart.de/ -* Login with your username and password () +Note: If you don't have an account create one. We allow anyone to host repositories +on our GitLab instance as long as it is DuMuX related. * Click the **New project** button * Follow the given instructions for an *existing folder* -**Important**: Before executing the `git add .` command, you should add your cmake build folder to gitignore. -The easiest way to do so is to just copy the *.gitignore* file from your dumux module into your module path. +**Important**: Before executing the `git add .` command, you should add your cmake build folder to `.gitignore`. +The easiest way to do so is to copy the `.gitignore` file from the dumux module into your module path. If everything +worked, executing `git status` should not show `build-cmake` anymore. Never put your executables or other build files +under version control. Only source files (`*.hh`, `*.cc`, `*.input`, `CMakeLists.txt`) should be under version control. -- GitLab From 0788511e16152a5e8fe6c3eee695c14e95f13081 Mon Sep 17 00:00:00 2001 From: Timo Koch Date: Thu, 21 Sep 2017 20:26:29 +0200 Subject: [PATCH 31/42] Update README.md ex2 --- tutorial/ex2/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tutorial/ex2/README.md b/tutorial/ex2/README.md index 996f741ec3..61587b3508 100644 --- a/tutorial/ex2/README.md +++ b/tutorial/ex2/README.md @@ -2,7 +2,7 @@
## Problem set-up -The problem setup is identical to the previous [_exercise 1_](../ex1/README.md) with a lower injection rate of 1e-6 kg/(m*s) so that diffusion plays a more dominant role in the transport process. +The problem setup is identical to the previous [_exercise 1_](../ex1/README.md). ## Preparing the exercise -- GitLab From c9e8319dce1cdc675da68d023940019c46d5e919 Mon Sep 17 00:00:00 2001 From: Timo Koch Date: Thu, 21 Sep 2017 20:27:42 +0200 Subject: [PATCH 32/42] Update README.md ex1 --- tutorial/ex1/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tutorial/ex1/README.md b/tutorial/ex1/README.md index fd88020936..0548a993fc 100644 --- a/tutorial/ex1/README.md +++ b/tutorial/ex1/README.md @@ -2,7 +2,7 @@
## Problem set-up -N2 is injected in an aquifer previously saturated with water with an injection rate of 0.001 kg/m*s. +N2 is injected in an aquifer previously saturated with water with an injection rate of 0.001 kg/(s*m$`^2`$). The aquifer is situated 2700 m below see level and the domain size is 60 m x 40 m. It consists of two layers, a moderately permeable one ($`\Omega_1`$) and a lower permeable one ($`\Omega_2`$). -- GitLab From 705f405df9950c918b28673aa7c17159a95b1f58 Mon Sep 17 00:00:00 2001 From: Timo Koch Date: Fri, 22 Sep 2017 15:49:22 +0200 Subject: [PATCH 33/42] Update README.md ex2 --- tutorial/ex2/README.md | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/tutorial/ex2/README.md b/tutorial/ex2/README.md index 61587b3508..dca532eb27 100644 --- a/tutorial/ex2/README.md +++ b/tutorial/ex2/README.md @@ -21,7 +21,7 @@ Locate all the files you will need for this exercise * The __input file__: `exercise2.input` * Two header files containing: * a custom __local residual__ in: `mylocalresidual.hh` - * a custom __material law__ in:: `mymateriallaw.hh` + * a custom __material law__ in: `mymateriallaw.hh`


@@ -40,10 +40,11 @@ cd build-cmake/tutorial/exercise2 make exercise2 ``` -* Execute the two problems and inspect the result +* Run the problem and inspect the result ```bash ./exercise2 +paraview *pvd ``` Note: Because the input file has the same name as the executable, DuMuX will find it automatically. @@ -84,9 +85,9 @@ SET_PROP(InjectionSpatialParams, MaterialLaw) Note: Also use the wrapper class `EffToAbsLaw`. It takes care of converting absolute to effective saturations considering residual saturations. `MyMaterialLaw` as other material laws (like Brooks-Corey, VanGenuchten, ...) in DuMuX only deals with effective saturations. -Verify your changes by recompiling and running the program. You should see a plot of your new function. +* Verify your changes by recompiling and running the program. You should see a plot of your new function. -For the next task disable the plotting feature by changing the settings in the input file `exercise2.input` +For the next task, disable the plotting feature by changing the settings in the input file `exercise2.input` ```ini [Problem] @@ -97,7 +98,7 @@ OnlyPlotMaterialLaws = false ### Task 4: Enable/Disable Gravity -> DuMuX parameters
-DuMuX has many parameters that have default values. For example, per default all simulation consider gravity effects. +DuMuX has many parameters that have default values. For example, all simulations consider gravity effects by default. You can disable gravity for a study, simply by setting the parameter in the input file ```ini @@ -108,7 +109,7 @@ EnableGravity = false Run the simulation with and without gravity. Change the `Problem.Name` parameter to create output files with different names. Compare the results using paraview. You should immediately see the difference. -A list of parameters that can be set through the input file are given [here](http://www.dumux.org/doxygen-stable/html-2.11/a06387.php). +A list of parameters that can be set through the input file is given [here](http://www.dumux.org/doxygen-stable/html-2.11/a06387.php).


@@ -142,7 +143,7 @@ MyTwoPTwoCLocalResidual() * Verify you are using the new class by compiling and running the new program and inspecting the terminal output. -You want to make the new local residual special by adding a switch enabling / disabling diffusion. We will achieve this with a DuMuX parameter, a parameter read from the input file that defaults to a property value if the input file doesn't contain the parameter. +You want to make the new local residual special by adding a switch enabling / disabling diffusion. We will achieve this with a DuMuX parameter which is read from the input file and defaults to a property value if the input file doesn't contain the parameter. * Create a new `TypeTag` node, a new `PropertyTag`, and set a default in the `mylocalresidual.hh` file by adding @@ -193,6 +194,8 @@ You can now enable and disable diffusion through the input file EnableDiffusion = true / false ``` -Verify the difference in the parameter $`x_w^{N2}`$, i.e. the mole fraction of nitrogen in the -water phase, with and without diffusion. Note that due to diffusion being a slow process you +* Verify the difference in the parameter $`x_w^{N2}`$, i.e. the mole fraction of nitrogen in the +water phase, with and without diffusion. + +Note that due to diffusion being a slow process you can only see the difference in later times. -- GitLab From 985dd65d05f8817b73217c3f7cd3ad10866e7abc Mon Sep 17 00:00:00 2001 From: Katharina Heck Date: Fri, 22 Sep 2017 16:06:35 +0200 Subject: [PATCH 34/42] [cleanup] adapt ex1 to changes in ex2 --- tutorial/ex1/README.md | 18 +- tutorial/ex1/exercise1.input | 20 +- tutorial/ex1/injection2p2cproblem.hh | 192 ++++------- tutorial/ex1/injection2pniproblem.hh | 72 ++-- tutorial/ex1/injection2pproblem.hh | 67 ++-- tutorial/ex1/injection2pspatialparams.hh | 98 +++--- tutorial/ex2/injection2p2cproblem.hh | 2 +- tutorial/solution/ex1/injection2p2cproblem.hh | 310 ++++++++++++++++++ tutorial/solution/ex1/injection2pniproblem.hh | 76 +++-- 9 files changed, 573 insertions(+), 282 deletions(-) create mode 100644 tutorial/solution/ex1/injection2p2cproblem.hh diff --git a/tutorial/ex1/README.md b/tutorial/ex1/README.md index 0548a993fc..a5757ce683 100644 --- a/tutorial/ex1/README.md +++ b/tutorial/ex1/README.md @@ -66,10 +66,13 @@ EntryPressureCoarse = 1e4 ### Task 4: Runtime parameters
-The injection rate is currently hard-coded in `injection2pproblem.hh`. +The injection rate is currently hard-coded in `injection2p2cproblem.hh` to $`1e-4 kg/(s m^2)`$. ```c++ -code snippet + // set the Neumann values for the Nitrogen component balance + // convert from units kg/(s*m^2) to mole/(s*m^2) +values[Indices::contiNEqIdx] = -1e-4/FluidSystem::molarMass(FluidSystem::nCompIdx); +values[Indices::contiWEqIdx] = 0.0; ``` We want to be able to set it at runtime. To this end, @@ -77,7 +80,7 @@ We want to be able to set it at runtime. To this end, ```c++ // read the injection rate from the input file at run time -const auto injectionRate = GET_RUNTIME_PARAM_FROM_GROUP(TypeTag, , , ); +const auto totalAreaSpecificInflow_ = GET_RUNTIME_PARAM_FROM_GROUP(TypeTag, , , ); ``` * Replace @@ -86,9 +89,14 @@ const auto injectionRate = GET_RUNTIME_PARAM_FROM_GROUP(TypeTag, , ` is the group in the input file * `` is the name of the parameter in the input file -Note that due to the way the macro works, the names are specified as plain text without "quotation marks". +Note that due to the way the macro works, the names are specified as plain text without "quotation marks". Follow the instructions given as a -* Check the influence of that parameter on the simulation result by rerunning the simulation with different injection rates. +```c++ +// TODO: dumux-course-task +``` +in the `injection2p2cproblem.hh` file and also remember to also set the parameter totalAreaSpecificInflow in the input file. + +* Check the influence of that parameter on the simulation result by rerunning the simulation with different injection rates. Remember to also set the parameter totalAreaSpecificInflow in the input file. Again, you don't need to recompile the program. diff --git a/tutorial/ex1/exercise1.input b/tutorial/ex1/exercise1.input index a4e055be8c..4f9a57e69a 100755 --- a/tutorial/ex1/exercise1.input +++ b/tutorial/ex1/exercise1.input @@ -1,6 +1,6 @@ [TimeManager] -DtInitial = 250 # [s] -TEnd = 1e7 # [s] +DtInitial = 3600 # in seconds +TEnd = 3.154e9 # in seconds, i.e ten years [Grid] LowerLeft = 0 0 @@ -8,11 +8,17 @@ UpperRight = 60 40 Cells = 24 16 [Problem] -MaxDepth = 2700.0 +Name = injection +OnlyPlotMaterialLaws = true +AquiferDepth = 2700.0 # m +InjectionDuration = 2.628e6 # in seconds, i.e. one month -[Newton] -WriteConvergence = 1 # write convergence behaviour to disk? +#TODO: dumux-course-task: +#set totalAreaSpecificInflow [SpatialParams] -EntryPressureFine = 4.5e4 -EntryPressureCoarse = 1e4 +PermeabilityAquitard = 1e-15 # m^2 +EntryPressureAquitard = 4.5e4 # Pa +PermeabilityAquifer = 1e-12 # m^2 +EntryPressureAquifer = 1e4 # Pa + diff --git a/tutorial/ex1/injection2p2cproblem.hh b/tutorial/ex1/injection2p2cproblem.hh index a63bc73d1c..aada803f77 100644 --- a/tutorial/ex1/injection2p2cproblem.hh +++ b/tutorial/ex1/injection2p2cproblem.hh @@ -64,21 +64,19 @@ SET_BOOL_PROP(Injection2p2cProblem, UseMoles, true); * \brief Problem where air is injected under a low permeable layer in a depth of 2700m. * * The domain is sized 60m times 40m and consists of two layers, a moderately - * permeable one (\f$ K=10e-12\f$) for \f$ y<22m\f$ and one with a lower permeablility (\f$ K=10e-13\f$) + * permeable one (\f$ K=10e-12\f$) and one with a lower permeablility (\f$ K=10e-13\f$) * in the rest of the domain. * - * A mixture of Nitrogen and Water vapor, which is composed according to the prevailing conditions (temperature, pressure) - * enters a water-filled aquifer. This is realized with a solution-dependent Neumann boundary condition at the right boundary + * Nitrogen is injected into a water-filled aquifer through a well. First, we inject for one month. + * Then, we continue simulating the development of the nitrogen plume for 10 years.This is realized with a solution-dependent Neumann boundary condition at the right boundary * (\f$ 7m./exercise1_2p2c -parameterFile exercise1.input> + * ./exercise1_2p2c -ParameterFile exercise1.input> */ template class Injection2p2cProblem : public ImplicitPorousMediaProblem @@ -89,45 +87,16 @@ class Injection2p2cProblem : public ImplicitPorousMediaProblem typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; typedef typename GET_PROP_TYPE(TypeTag, FluidSystem) FluidSystem; - enum { - // Grid and world dimension - dim = GridView::dimension, - dimWorld = GridView::dimensionworld - }; + // grid world dimension + static constexpr auto dimWorld = GridView::dimensionworld; - // copy some indices for convenience typedef typename GET_PROP_TYPE(TypeTag, Indices) Indices; - enum { - wPhaseIdx = Indices::wPhaseIdx, - nPhaseIdx = Indices::nPhaseIdx, - - - wCompIdx = FluidSystem::wCompIdx, - nCompIdx = FluidSystem::nCompIdx, - - contiH2OEqIdx = Indices::contiWEqIdx, - contiN2EqIdx = Indices::contiNEqIdx - }; - - typedef typename GET_PROP_TYPE(TypeTag, PrimaryVariables) PrimaryVariables; - typedef typename GET_PROP_TYPE(TypeTag, ElementVolumeVariables) ElementVolumeVariables; typedef typename GET_PROP_TYPE(TypeTag, BoundaryTypes) BoundaryTypes; typedef typename GET_PROP_TYPE(TypeTag, TimeManager) TimeManager; - - typedef typename GridView::template Codim<0>::Entity Element; - typedef typename GridView::template Codim::Entity Vertex; - typedef typename GridView::Intersection Intersection; - - typedef typename GET_PROP_TYPE(TypeTag, FVElementGeometry) FVElementGeometry; - + typedef typename GET_PROP_TYPE(TypeTag, MaterialLaw) MaterialLaw; typedef Dune::FieldVector GlobalPosition; - enum { isBox = GET_PROP_VALUE(TypeTag, ImplicitIsBox) }; - - //! property that defines whether mole or mass fractions are used - static const bool useMoles = GET_PROP_VALUE(TypeTag, UseMoles); - public: /*! * \brief The constructor @@ -139,8 +108,6 @@ public: const GridView &gridView) : ParentType(timeManager, gridView) { - maxDepth_ = GET_RUNTIME_PARAM(TypeTag, Scalar, Problem.MaxDepth); - // initialize the tables of the fluid system FluidSystem::init(/*tempMin=*/273.15, /*tempMax=*/423.15, @@ -149,15 +116,16 @@ public: /*pMax=*/30e6, /*numP=*/300); - //stateing in the console whether mole or mass fractions are used - if(useMoles) - { - std::cout<<"problem uses mole-fractions"<model().globalPhaseStorage(storageW, wPhaseIdx); - this->model().globalPhaseStorage(storageN, nPhaseIdx); + this->model().globalPhaseStorage(storageW, Indices::wPhaseIdx); + this->model().globalPhaseStorage(storageN, Indices::nPhaseIdx); // Write mass balance information for rank 0 if (this->gridView().comm().rank() == 0) { @@ -190,8 +158,8 @@ public: * * This is used as a prefix for files generated by the simulation. */ - const std::string name() const - { return "injection-2p2c"; } + std::string name() const + { return name_+"-2p2c"; } /*! * \brief Returns the temperature \f$ K \f$ @@ -231,8 +199,11 @@ public: void boundaryTypesAtPos(BoundaryTypes &values, const GlobalPosition &globalPos) const { - if (globalPos[0] < eps_) + if (globalPos[dimWorld-1] < eps_) values.setAllDirichlet(); + + // and Neuman boundary conditions everywhere else + // note that we don't differentiate between Neumann and Robin boundary types else values.setAllNeumann(); } @@ -247,49 +218,34 @@ public: */ void dirichletAtPos(PrimaryVariables &values, const GlobalPosition &globalPos) const { - initial_(values, globalPos); + initialAtPos(values, globalPos); } /*! - * \brief Evaluates the boundary conditions for a Neumann - * boundary segment in dependency on the current solution. + * \brief Evaluates the boundary conditions for a Neumann boundary segment. * * \param values Stores the Neumann values for the conservation equations in * \f$ [ \textnormal{unit of conserved quantity} / (m^(dim-1) \cdot s )] \f$ - * \param element The finite element - * \param fvGeometry The finite volume geometry of the element - * \param intersection The intersection between element and boundary - * \param scvIdx The local index of the sub-control volume - * \param boundaryFaceIdx The index of the boundary face - * \param elemVolVars All volume variables for the element - * - * This method is used for cases, when the Neumann condition depends on the - * solution and requires some quantities that are specific to the fully-implicit method. - * The \a values store the mass flux of each phase normal to the boundary. - * Negative values indicate an inflow. + * \param globalPos The globalPosition of the boundary interface */ - void solDependentNeumann(PrimaryVariables &values, - const Element &element, - const FVElementGeometry &fvGeometry, - const Intersection &intersection, - const int scvIdx, - const int boundaryFaceIdx, - const ElementVolumeVariables &elemVolVars) const + void neumannAtPos(PrimaryVariables &values, + const GlobalPosition &globalPos) const { + // initialize values to zero, i.e. no-flow Neumann boundary conditions values = 0; - GlobalPosition globalPos; - if (isBox) - globalPos = element.geometry().corner(scvIdx); - else - globalPos = intersection.geometry().center(); - - Scalar injectedPhaseMass = 1e-3; - Scalar moleFracW = elemVolVars[scvIdx].moleFraction(nPhaseIdx, wCompIdx); - if (globalPos[1] < 15 + eps_ && globalPos[1] > 7 -eps_) { - values[contiN2EqIdx] = -(1-moleFracW)*injectedPhaseMass/FluidSystem::molarMass(nCompIdx); //mole/(m^2*s) -> kg/(s*m^2) - values[contiH2OEqIdx] = -moleFracW*injectedPhaseMass/FluidSystem::molarMass(wCompIdx); //mole/(m^2*s) -> kg/(s*m^2) - } + //if we are inside the injection zone set inflow Neumann boundary conditions + if (this->timeManager().time() + this->timeManager().timeStepSize() < injectionDuration_ + && globalPos[1] < 15 + eps_ && globalPos[1] > 7 - eps_ && globalPos[0] > 0.9*this->bBoxMax()[0]) + { + // TODO: dumux-course-task + //instead of setting -1e-4 here directly use totalAreaSpecificInflow_ in the computation + + // set the Neumann values for the Nitrogen component balance + // convert from units kg/(s*m^2) to mole/(s*m^2) + values[Indices::contiNEqIdx] = -1e-4/FluidSystem::molarMass(FluidSystem::nCompIdx); + values[Indices::contiWEqIdx] = 0.0; + } } // \} @@ -308,7 +264,23 @@ public: */ void initialAtPos(PrimaryVariables &values, const GlobalPosition &globalPos) const { - initial_(values, globalPos); + // 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]); + + // initially we have some nitrogen dissolved + // saturation mole fraction would be + // moleFracLiquidN2 = (pw + pc + p_vap^sat)/henry; + const Scalar moleFracLiquidN2 = pw*0.95/BinaryCoeff::H2O_N2::henry(temperature()); + + // note that because we start with a single phase system the primary variables + // are pl and x^w_N2. This will switch as soon after we start injecting to a two + // phase system so the primary variables will be pl and Sn (non-wetting saturation). + values[Indices::switchIdx] = moleFracLiquidN2; + values[Indices::pressureIdx] = pw; } /*! @@ -322,44 +294,12 @@ public: // \} private: - /*! - * \brief Evaluates the initial values for a control volume - * - * The internal method for the initial condition - * - * \param values Stores the initial values for the conservation equations in - * \f$ [ \textnormal{unit of primary variables} ] \f$ - * \param globalPos The global position - */ - void initial_(PrimaryVariables &values, - const GlobalPosition &globalPos) const - { - Scalar densityW = FluidSystem::H2O::liquidDensity(temperature(), 1e5); - - Scalar pl = 1e5 - densityW*this->gravity()[1]*(maxDepth_ - globalPos[1]); - Scalar moleFracLiquidN2 = pl*0.95/BinaryCoeff::H2O_N2::henry(temperature()); - Scalar moleFracLiquidH2O = 1.0 - moleFracLiquidN2; - - Scalar meanM = - FluidSystem::molarMass(wCompIdx)*moleFracLiquidH2O + - FluidSystem::molarMass(nCompIdx)*moleFracLiquidN2; - if(useMoles) - { - //mole-fraction formulation - values[Indices::switchIdx] = moleFracLiquidN2; - } - else - { - //mass fraction formulation - Scalar massFracLiquidN2 = moleFracLiquidN2*FluidSystem::molarMass(nCompIdx)/meanM; - values[Indices::switchIdx] = massFracLiquidN2; - } - values[Indices::pressureIdx] = pl; - } - - static constexpr Scalar eps_ = 1e-6; - Scalar maxDepth_; + std::string name_; //! Problem name + Scalar aquiferDepth_; //! Depth of the aquifer in m + Scalar injectionDuration_; //! Duration of the injection in seconds + //TODO: dumux-course-task + //define the Scalar totalAreaSpecificInflow_ here }; } //end namespace diff --git a/tutorial/ex1/injection2pniproblem.hh b/tutorial/ex1/injection2pniproblem.hh index 6a964f537f..f745385184 100644 --- a/tutorial/ex1/injection2pniproblem.hh +++ b/tutorial/ex1/injection2pniproblem.hh @@ -137,8 +137,6 @@ public: InjectionProblem2PNI(TimeManager &timeManager, const GridView &gridView) : ParentType(timeManager, gridView) { - maxDepth_ = GET_RUNTIME_PARAM(TypeTag, Scalar, Problem.MaxDepth); - // initialize the tables of the fluid system FluidSystem::init(/*tempMin=*/273.15, /*tempMax=*/423.15, @@ -146,6 +144,14 @@ public: /*pMin=*/0.0, /*pMax=*/30e6, /*numP=*/300); + + // name of the problem and output file + name_ = GET_RUNTIME_PARAM_FROM_GROUP(TypeTag, std::string, Problem, Name); + // depth of the aquifer, units: m + aquiferDepth_ = GET_RUNTIME_PARAM_FROM_GROUP(TypeTag, Scalar, Problem, AquiferDepth); + // inflow rate of nitrogen water vapor mixture, units: kg/(s m^2) + // the duration of the injection, units: second + injectionDuration_ = GET_RUNTIME_PARAM_FROM_GROUP(TypeTag, Scalar, Problem, InjectionDuration); } /*! @@ -212,8 +218,14 @@ public: */ void dirichletAtPos(PrimaryVariables &values, const GlobalPosition &globalPos) const { - Scalar densityW = 1000.0; - values[pressureIdx] = 1e5 + (maxDepth_ - globalPos[1])*densityW*9.81; + // assume a constant density + const Scalar densityW = 1000; + + // 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[saturationIdx] = 0.0; /*! * TODO:dumux-course-task: @@ -223,38 +235,25 @@ public: } /*! - * \brief Evaluate the boundary conditions for a neumann - * boundary segment. + * \brief Evaluates the boundary conditions for a Neumann boundary segment. * * \param values Stores the Neumann values for the conservation equations in * \f$ [ \textnormal{unit of conserved quantity} / (m^(dim-1) \cdot s )] \f$ - * \param element The finite element - * \param fvGeometry The finite volume geometry of the element - * \param intersection The intersection between element and boundary - * \param scvIdx The local index of the sub-control volume - * \param boundaryFaceIdx The index of the boundary face - * - * The \a values store the mass flux of each phase normal to the boundary. - * Negative values indicate an inflow. + * \param globalPos The globalPosition of the boundary interface */ - void neumann(PrimaryVariables &values, - const Element &element, - const FVElementGeometry &fvGeometry, - const Intersection &intersection, - int scvIdx, - int boundaryFaceIdx) const + void neumannAtPos(PrimaryVariables &values, + const GlobalPosition &globalPos) const { + // initialize values to zero, i.e. no-flow Neumann boundary conditions + values = 0; values = 0; - GlobalPosition globalPos; - if (isBox) - globalPos = element.geometry().corner(scvIdx); - else - globalPos = intersection.geometry().center(); - - if (globalPos[1] < 15 + eps_ && globalPos[1] > 7 - eps_) { + if (this->timeManager().time() + this->timeManager().timeStepSize() < injectionDuration_ + && globalPos[1] < 15 + eps_ && globalPos[1] > 7 - eps_ && globalPos[0] > 0.9*this->bBoxMax()[0]) + { // inject air. negative values mean injection - values[contiNEqIdx] = -1e-3; // kg/(s*m^2) + values[Indices::contiNEqIdx] = -1e-4; // kg/(s*m^2) + values[Indices::contiWEqIdx] = 0.0; } } @@ -275,8 +274,14 @@ public: */ void initialAtPos(PrimaryVariables &values, const GlobalPosition &globalPos) const { - Scalar densityW = 1000.0; - values[pressureIdx] = 1e5 + (maxDepth_ - globalPos[1])*densityW*9.81; + // assume a constant density + const Scalar densityW = 1000; + + // 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[saturationIdx] = 0.0; /*! @@ -289,9 +294,10 @@ public: private: - Scalar maxDepth_; - static constexpr Scalar eps_ = 1.5e-7; - std::string name_; + 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 }; } //end namespace diff --git a/tutorial/ex1/injection2pproblem.hh b/tutorial/ex1/injection2pproblem.hh index fbf085c328..c990ffb09b 100644 --- a/tutorial/ex1/injection2pproblem.hh +++ b/tutorial/ex1/injection2pproblem.hh @@ -123,8 +123,6 @@ public: InjectionProblem2P(TimeManager &timeManager, const GridView &gridView) : ParentType(timeManager, gridView) { - maxDepth_ = GET_RUNTIME_PARAM(TypeTag, Scalar, Problem.MaxDepth); - // initialize the tables of the fluid system FluidSystem::init(/*tempMin=*/273.15, /*tempMax=*/423.15, @@ -132,6 +130,14 @@ public: /*pMin=*/0.0, /*pMax=*/30e6, /*numP=*/300); + + // name of the problem and output file + name_ = GET_RUNTIME_PARAM_FROM_GROUP(TypeTag, std::string, Problem, Name); + // depth of the aquifer, units: m + aquiferDepth_ = GET_RUNTIME_PARAM_FROM_GROUP(TypeTag, Scalar, Problem, AquiferDepth); + // inflow rate of nitrogen water vapor mixture, units: kg/(s m^2) + // the duration of the injection, units: second + injectionDuration_ = GET_RUNTIME_PARAM_FROM_GROUP(TypeTag, Scalar, Problem, InjectionDuration); } /*! @@ -204,50 +210,34 @@ public: */ void dirichletAtPos(PrimaryVariables &values, const GlobalPosition &globalPos) const { - Scalar densityW = FluidSystem::H2O::liquidDensity(temperature(), 1e5); - values[pressureIdx] = 1e5 + (maxDepth_ - globalPos[1])*densityW*9.81; - values[saturationIdx] = 0.0; + initialAtPos(values, globalPos); } /*! - * \brief Evaluate the boundary conditions for a neumann - * boundary segment. + * \brief Evaluates the boundary conditions for a Neumann boundary segment. * * \param values Stores the Neumann values for the conservation equations in * \f$ [ \textnormal{unit of conserved quantity} / (m^(dim-1) \cdot s )] \f$ - * \param element The finite element - * \param fvGeometry The finite volume geometry of the element - * \param intersection The intersection between element and boundary - * \param scvIdx The local index of the sub-control volume - * \param boundaryFaceIdx The index of the boundary face - * - * The \a values store the mass flux of each phase normal to the boundary. - * Negative values indicate an inflow. + * \param globalPos The globalPosition of the boundary interface */ - void neumann(PrimaryVariables &values, - const Element &element, - const FVElementGeometry &fvGeometry, - const Intersection &intersection, - int scvIdx, - int boundaryFaceIdx) const + void neumannAtPos(PrimaryVariables &values, + const GlobalPosition &globalPos) const { + // initialize values to zero, i.e. no-flow Neumann boundary conditions + values = 0; values = 0; - GlobalPosition globalPos; - if (isBox) - globalPos = element.geometry().corner(scvIdx); - else - globalPos = intersection.geometry().center(); - - if (globalPos[1] < 15 + eps_ && globalPos[1] > 7 - eps_) { + if (this->timeManager().time() + this->timeManager().timeStepSize() < injectionDuration_ + && globalPos[1] < 15 + eps_ && globalPos[1] > 7 - eps_ && globalPos[0] > 0.9*this->bBoxMax()[0]) + { // inject air. negative values mean injection - values[contiNEqIdx] = -1e-3; // kg/(s*m^2) + values[Indices::contiNEqIdx] = -1e-4; // kg/(s*m^2) + values[Indices::contiWEqIdx] = 0.0; } } // \} - /*! * \name Volume terms */ @@ -262,15 +252,24 @@ public: */ void initialAtPos(PrimaryVariables &values, const GlobalPosition &globalPos) const { - Scalar densityW = FluidSystem::H2O::liquidDensity(temperature(), 1e5); - values[pressureIdx] = 1e5 + (maxDepth_ - globalPos[1])*densityW*9.81; + + // 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[saturationIdx] = 0.0; } // \} private: - Scalar maxDepth_; - static constexpr Scalar eps_ = 1.5e-7; + 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 }; } //end namespace diff --git a/tutorial/ex1/injection2pspatialparams.hh b/tutorial/ex1/injection2pspatialparams.hh index fc85aa4c21..95071e887b 100644 --- a/tutorial/ex1/injection2pspatialparams.hh +++ b/tutorial/ex1/injection2pspatialparams.hh @@ -31,6 +31,9 @@ #include #include +#include +#include + #include namespace Dumux @@ -93,34 +96,34 @@ public: InjectionSpatialParams(const GridView &gridView) : ParentType(gridView) { - layerBottom_ = 25.0; + aquiferHeightFromBottom_ = 30.0; // intrinsic permeabilities - fineK_ = 1e-13; - coarseK_ = 1e-12; + aquitardK_ = GET_RUNTIME_PARAM(TypeTag, Scalar, SpatialParams.PermeabilityAquitard); + aquiferK_ = GET_RUNTIME_PARAM(TypeTag, Scalar, SpatialParams.PermeabilityAquifer); // porosities - finePorosity_ = 0.2; - coarsePorosity_ = 0.4; - - //materialLawParams - fineEntryPressure_ = GET_RUNTIME_PARAM(TypeTag, Scalar, SpatialParams.EntryPressureFine); - coarseEntryPressure_ = GET_RUNTIME_PARAM(TypeTag, Scalar, SpatialParams.EntryPressureCoarse); - - // heat conductivity of granite - lambdaSolid_ = 2.8; + aquitardPorosity_ = 0.2; + aquiferPorosity_ = 0.4; // residual saturations - fineMaterialParams_.setSwr(0.2); - fineMaterialParams_.setSnr(0.0); - coarseMaterialParams_.setSwr(0.2); - coarseMaterialParams_.setSnr(0.0); + aquitardMaterialParams_.setSwr(0.2); + aquitardMaterialParams_.setSnr(0.0); + aquiferMaterialParams_.setSwr(0.2); + aquiferMaterialParams_.setSnr(0.0); // parameters for the Brooks-Corey law - fineMaterialParams_.setPe(fineEntryPressure_); - coarseMaterialParams_.setPe(coarseEntryPressure_); - fineMaterialParams_.setLambda(2.0); - coarseMaterialParams_.setLambda(2.0); + aquitardMaterialParams_.setPe(GET_RUNTIME_PARAM(TypeTag, Scalar, SpatialParams.EntryPressureAquitard)); + aquiferMaterialParams_.setPe(GET_RUNTIME_PARAM(TypeTag, Scalar, SpatialParams.EntryPressureAquifer)); + aquitardMaterialParams_.setLambda(2.0); + aquiferMaterialParams_.setLambda(2.0); + + // plot the material laws using gnuplot and exit + if (GET_RUNTIME_PARAM(TypeTag, bool, Problem.OnlyPlotMaterialLaws)) + { + plotMaterialLaws(); + exit(0); + } } /*! @@ -135,9 +138,9 @@ public: const int scvIdx) const { const GlobalPosition &globalPos = fvGeometry.subContVol[scvIdx].global; - if (isFineMaterial_(globalPos)) - return fineK_; - return coarseK_; + if (isInAquitard_(globalPos)) + return aquitardK_; + return aquiferK_; } /*! @@ -152,9 +155,9 @@ public: const int scvIdx) const { const GlobalPosition &globalPos = fvGeometry.subContVol[scvIdx].global; - if (isFineMaterial_(globalPos)) - return finePorosity_; - return coarsePorosity_; + if (isInAquitard_(globalPos)) + return aquitardPorosity_; + return aquiferPorosity_; } @@ -171,9 +174,9 @@ public: const int scvIdx) const { const GlobalPosition &globalPos = fvGeometry.subContVol[scvIdx].global; - if (isFineMaterial_(globalPos)) - return fineMaterialParams_; - return coarseMaterialParams_; + if (isInAquitard_(globalPos)) + return aquitardMaterialParams_; + return aquiferMaterialParams_; } /*! @@ -228,24 +231,37 @@ public: // return lambdaSolid_; // } + /*! + * \brief Creates a gnuplot output of the pc-Sw curve + */ + void plotMaterialLaws() + { + PlotMaterialLaw plotMaterialLaw; + GnuplotInterface gnuplot; + plotMaterialLaw.addpcswcurve(gnuplot, aquitardMaterialParams_, 0.2, 1.0, "upper layer (fine, aquitard)", "w lp"); + plotMaterialLaw.addpcswcurve(gnuplot, aquiferMaterialParams_, 0.2, 1.0, "lower layer (coarse, aquifer)", "w l"); + gnuplot.setOption("set xrange [0:1]"); + gnuplot.setOption("set label \"residual\\nsaturation\" at 0.1,100000 center"); + gnuplot.plot("pc-Sw"); + } + private: - bool isFineMaterial_(const GlobalPosition &globalPos) const - { return globalPos[dimWorld-1] > layerBottom_; } - Scalar fineK_; - Scalar coarseK_; - Scalar layerBottom_; + static constexpr Scalar eps_ = 1e-6; + + bool isInAquitard_(const GlobalPosition &globalPos) const + { return globalPos[dimWorld-1] > aquiferHeightFromBottom_ + eps_; } - Scalar finePorosity_; - Scalar coarsePorosity_; + Scalar aquitardK_; + Scalar aquiferK_; + Scalar aquiferHeightFromBottom_; - Scalar lambdaSolid_; - Scalar fineEntryPressure_; - Scalar coarseEntryPressure_; + Scalar aquitardPorosity_; + Scalar aquiferPorosity_; - MaterialLawParams fineMaterialParams_; - MaterialLawParams coarseMaterialParams_; + MaterialLawParams aquitardMaterialParams_; + MaterialLawParams aquiferMaterialParams_; }; } diff --git a/tutorial/ex2/injection2p2cproblem.hh b/tutorial/ex2/injection2p2cproblem.hh index cf45851a5b..6b611593e1 100644 --- a/tutorial/ex2/injection2p2cproblem.hh +++ b/tutorial/ex2/injection2p2cproblem.hh @@ -74,7 +74,7 @@ SET_BOOL_PROP(Injection2p2cProblem, UseMoles, true); * \brief Problem where air is injected under a low permeable layer in a depth of 2700m. * * The domain is sized 60m times 40m and consists of two layers, a moderately - * permeable one (\f$ K=10e-12\f$) for \f$ y<22m\f$ and one with a lower permeablility (\f$ K=10e-13\f$) + * permeable one for \f$ y<22m\f$ and one with a lower permeablility * in the rest of the domain. * * Nitrogen is injected into a water-filled aquifer through a well. First, we inject for one month. diff --git a/tutorial/solution/ex1/injection2p2cproblem.hh b/tutorial/solution/ex1/injection2p2cproblem.hh new file mode 100644 index 0000000000..e03f339f15 --- /dev/null +++ b/tutorial/solution/ex1/injection2p2cproblem.hh @@ -0,0 +1,310 @@ +// -*- 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 Problem where air is injected under a low permeable layer in a depth of 2700m. + */ +#ifndef DUMUX_INJECTION_2P2C_PROBLEM_HH +#define DUMUX_INJECTION_2P2C_PROBLEM_HH + +#include +#include +#include + +#include "injection2p2cspatialparams.hh" + +namespace Dumux +{ + +// foward declaration +template +class Injection2p2cProblem; + +// setup property TypeTag +namespace Properties +{ + +// inherit from MyLocalResidualParams +NEW_TYPE_TAG(Injection2p2cProblem, INHERITS_FROM(TwoPTwoC, InjectionSpatialParams)); +NEW_TYPE_TAG(Injection2p2cBoxProblem, INHERITS_FROM(BoxModel, Injection2p2cProblem)); +NEW_TYPE_TAG(Injection2p2pcCCProblem, INHERITS_FROM(CCModel, Injection2p2cProblem)); + +// Set the grid type +SET_TYPE_PROP(Injection2p2cProblem, Grid, Dune::YaspGrid<2>); + +// Set the problem property +SET_TYPE_PROP(Injection2p2cProblem, Problem, Injection2p2cProblem); + +// Set fluid configuration +SET_TYPE_PROP(Injection2p2cProblem, + FluidSystem, + FluidSystems::H2ON2); + +// Define whether mole(true) or mass (false) fractions are used +SET_BOOL_PROP(Injection2p2cProblem, UseMoles, true); + +} // end namespace Properties + +/*! + * \ingroup TwoPTwoCModel + * \ingroup ImplicitTestProblems + * \brief Problem where air is injected under a low permeable layer in a depth of 2700m. + * + * The domain is sized 60m times 40m and consists of two layers, a moderately + * permeable one for \f$ y<22m\f$ and one with a lower permeablility + * in the rest of the domain. + * + * Nitrogen is injected into a water-filled aquifer through a well. First, we inject for one month. + * Then, we continue simulating the development of the nitrogen plume for 10 years. + * This is realized with a Neumann boundary condition at the right boundary + * (\f$ 7m +class Injection2p2cProblem : public ImplicitPorousMediaProblem +{ + typedef ImplicitPorousMediaProblem ParentType; + + typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; + typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; + typedef typename GET_PROP_TYPE(TypeTag, FluidSystem) FluidSystem; + + // grid world dimension + static constexpr auto dimWorld = GridView::dimensionworld; + + typedef typename GET_PROP_TYPE(TypeTag, Indices) Indices; + typedef typename GET_PROP_TYPE(TypeTag, PrimaryVariables) PrimaryVariables; + typedef typename GET_PROP_TYPE(TypeTag, BoundaryTypes) BoundaryTypes; + typedef typename GET_PROP_TYPE(TypeTag, TimeManager) TimeManager; + typedef typename GET_PROP_TYPE(TypeTag, MaterialLaw) MaterialLaw; + typedef Dune::FieldVector GlobalPosition; + +public: + /*! + * \brief The constructor + * + * \param timeManager The time manager + * \param gridView The grid view + */ + Injection2p2cProblem(TimeManager &timeManager, const GridView &gridView) + : ParentType(timeManager, gridView) + { + // 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 + name_ = GET_RUNTIME_PARAM_FROM_GROUP(TypeTag, std::string, Problem, Name); + // depth of the aquifer, units: m + aquiferDepth_ = GET_RUNTIME_PARAM_FROM_GROUP(TypeTag, Scalar, Problem, AquiferDepth); + // inflow rate of nitrogen water vapor mixture, units: kg/(s m^2) + totalAreaSpecificInflow_ = GET_RUNTIME_PARAM_FROM_GROUP(TypeTag, Scalar, Problem, TotalAreaSpecificInflow); + // the duration of the injection, units: second + injectionDuration_ = GET_RUNTIME_PARAM_FROM_GROUP(TypeTag, Scalar, Problem, InjectionDuration); + } + + /*! + * \brief User defined output after the time integration + * + * Will be called diretly after the time integration + */ + void postTimeStep() + { + // Calculate storage terms + PrimaryVariables storageW, storageN; + this->model().globalPhaseStorage(storageW, Indices::wPhaseIdx); + this->model().globalPhaseStorage(storageN, Indices::nPhaseIdx); + + // Write mass balance information for rank 0 + if (this->gridView().comm().rank() == 0) + { + std::cout <<"Storage: wetting=[" << storageW << "]" + << " nonwetting=[" << storageN << "]" << std::endl; + } + } + + /*! + * \name Problem parameters + */ + // \{ + + /*! + * \brief Returns the problem name + * + * This is used as a prefix for files generated by the simulation. + */ + const std::string& name() const + { return name_; } + + /*! + * \brief Returns the temperature in \f$ K \f$ + */ + Scalar temperature() const + { return 273.15 + 30; } + + /*! + * \brief Returns the source term + * + * \param values Stores the source values for the conservation equations in + * \f$ [ \textnormal{unit of primary variable} / (m^\textrm{dim} \cdot s )] \f$ + * \param globalPos The global position + */ + void sourceAtPos(PrimaryVariables &values, + const GlobalPosition &globalPos) const + { values = 0; } + + // \} + + /*! + * \name Boundary conditions + */ + // \{ + + /*! + * \brief Specifies which kind of boundary condition should be + * used for which equation on a given boundary segment + * + * \param values Stores the value of the boundary type + * \param globalPos The global position + */ + void boundaryTypesAtPos(BoundaryTypes &values, + const GlobalPosition &globalPos) const + { + // Set Dirichlet at the bottom of the domain + if (globalPos[dimWorld-1] < eps_) + { + values.setAllDirichlet(); + } + + // and Neuman boundary conditions everywhere else + // note that we don't differentiate between Neumann and Robin boundary types + else + { + values.setAllNeumann(); + } + } + + /*! + * \brief Evaluates the boundary conditions for a Dirichlet + * boundary segment + * + * \param values Stores the Dirichlet values for the conservation equations in + * \f$ [ \textnormal{unit of primary variable} ] \f$ + * \param globalPos The global position + */ + void dirichletAtPos(PrimaryVariables &values, const GlobalPosition &globalPos) const + { initialAtPos(values, globalPos); } + + /*! + * \brief Evaluates the boundary conditions for a Neumann boundary segment. + * + * \param values Stores the Neumann values for the conservation equations in + * \f$ [ \textnormal{unit of conserved quantity} / (m^(dim-1) \cdot s )] \f$ + * \param globalPos The globalPosition of the boundary interface + */ + void neumannAtPos(PrimaryVariables &values, + const GlobalPosition &globalPos) const + { + // initialize values to zero, i.e. no-flow Neumann boundary conditions + values = 0; + + //if we are inside the injection zone set inflow Neumann boundary conditions + if (this->timeManager().time() + this->timeManager().timeStepSize() < injectionDuration_ + && globalPos[1] < 15 + eps_ && globalPos[1] > 7 - eps_ && globalPos[0] > 0.9*this->bBoxMax()[0]) + { + // set the Neumann values for the Nitrogen component balance + // convert from units kg/(s*m^2) to mole/(s*m^2) + values[Indices::contiNEqIdx] = -totalAreaSpecificInflow_/FluidSystem::molarMass(FluidSystem::nCompIdx); + values[Indices::contiWEqIdx] = 0.0; + } + } + + // \} + + /*! + * \name Volume terms + */ + // \{ + + /*! + * \brief Evaluates the initial values for a control volume + * + * \param values Stores the initial values for the conservation equations in + * \f$ [ \textnormal{unit of primary variables} ] \f$ + * \param globalPos The global position + */ + void initialAtPos(PrimaryVariables &values, const GlobalPosition &globalPos) const + { + // 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]); + + // initially we have some nitrogen dissolved + // saturation mole fraction would be + // moleFracLiquidN2 = (pw + pc + p_vap^sat)/henry; + const Scalar moleFracLiquidN2 = pw*0.95/BinaryCoeff::H2O_N2::henry(temperature()); + + // note that because we start with a single phase system the primary variables + // are pl and x^w_N2. This will switch as soon after we start injecting to a two + // phase system so the primary variables will be pl and Sn (non-wetting saturation). + values[Indices::switchIdx] = moleFracLiquidN2; + values[Indices::pressureIdx] = pw; + } + + /*! + * \brief Return the initial phase state inside a control volume. + * + * \param globalPos The global position + * \note we start with a single phase system + */ + int initialPhasePresenceAtPos(const GlobalPosition &globalPos) const + { return Indices::wPhaseOnly; } + + // \} + + //! If we should write restart files + bool shouldWriteRestartFile() const + { return false; } + +private: + static constexpr Scalar eps_ = 1e-6; + std::string name_; //! Problem name + Scalar aquiferDepth_; //! Depth of the aquifer in m + Scalar totalAreaSpecificInflow_; //! Area specific inflow rate in mole/(s*m^2) + Scalar injectionDuration_; //! Duration of the injection in seconds +}; + +} // end namespace Dumux + +#endif diff --git a/tutorial/solution/ex1/injection2pniproblem.hh b/tutorial/solution/ex1/injection2pniproblem.hh index 7bba02cae5..a023716ea2 100644 --- a/tutorial/solution/ex1/injection2pniproblem.hh +++ b/tutorial/solution/ex1/injection2pniproblem.hh @@ -130,8 +130,6 @@ public: InjectionProblem2PNI(TimeManager &timeManager, const GridView &gridView) : ParentType(timeManager, gridView) { - maxDepth_ = GET_RUNTIME_PARAM(TypeTag, Scalar, Problem.MaxDepth); - // initialize the tables of the fluid system FluidSystem::init(/*tempMin=*/273.15, /*tempMax=*/423.15, @@ -139,6 +137,14 @@ public: /*pMin=*/0.0, /*pMax=*/30e6, /*numP=*/300); + + // name of the problem and output file + name_ = GET_RUNTIME_PARAM_FROM_GROUP(TypeTag, std::string, Problem, Name); + // depth of the aquifer, units: m + aquiferDepth_ = GET_RUNTIME_PARAM_FROM_GROUP(TypeTag, Scalar, Problem, AquiferDepth); + // inflow rate of nitrogen water vapor mixture, units: kg/(s m^2) + // the duration of the injection, units: second + injectionDuration_ = GET_RUNTIME_PARAM_FROM_GROUP(TypeTag, Scalar, Problem, InjectionDuration); } /*! @@ -205,46 +211,39 @@ public: */ void dirichletAtPos(PrimaryVariables &values, const GlobalPosition &globalPos) const { - Scalar densityW = 1000.0; - values[pressureIdx] = 1e5 + (maxDepth_ - globalPos[1])*densityW*9.81; + // assume a constant density + const Scalar densityW = 1000; + + // 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[saturationIdx] = 0.0; - values[temperatureIdx] = 283.0 + (maxDepth_ - globalPos[1])*0.03; + values[temperatureIdx] = 283.0 + (aquiferDepth_ - globalPos[1])*0.03; } /*! - * \brief Evaluate the boundary conditions for a neumann - * boundary segment. + * \brief Evaluates the boundary conditions for a Neumann boundary segment. * * \param values Stores the Neumann values for the conservation equations in * \f$ [ \textnormal{unit of conserved quantity} / (m^(dim-1) \cdot s )] \f$ - * \param element The finite element - * \param fvGeometry The finite volume geometry of the element - * \param intersection The intersection between element and boundary - * \param scvIdx The local index of the sub-control volume - * \param boundaryFaceIdx The index of the boundary face - * - * The \a values store the mass flux of each phase normal to the boundary. - * Negative values indicate an inflow. + * \param globalPos The globalPosition of the boundary interface */ - void neumann(PrimaryVariables &values, - const Element &element, - const FVElementGeometry &fvGeometry, - const Intersection &intersection, - int scvIdx, - int boundaryFaceIdx) const + void neumannAtPos(PrimaryVariables &values, + const GlobalPosition &globalPos) const { + // initialize values to zero, i.e. no-flow Neumann boundary conditions + values = 0; values = 0; - GlobalPosition globalPos; - if (isBox) - globalPos = element.geometry().corner(scvIdx); - else - globalPos = intersection.geometry().center(); - - if (globalPos[1] < 15 + eps_ && globalPos[1] > 7 - eps_) { + if (this->timeManager().time() + this->timeManager().timeStepSize() < injectionDuration_ + && globalPos[1] < 15 + eps_ && globalPos[1] > 7 - eps_ && globalPos[0] > 0.9*this->bBoxMax()[0]) + { // inject air. negative values mean injection - values[contiNEqIdx] = -1e-3; // kg/(s*m^2) + values[Indices::contiNEqIdx] = -1e-4; // kg/(s*m^2) + values[Indices::contiWEqIdx] = 0.0; } } @@ -265,20 +264,27 @@ public: */ void initialAtPos(PrimaryVariables &values, const GlobalPosition &globalPos) const { - Scalar densityW = 1000.0; - values[pressureIdx] = 1e5 + (maxDepth_ - globalPos[1])*densityW*9.81; + // assume a constant density + const Scalar densityW = 1000; + + // 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[saturationIdx] = 0.0; - values[temperatureIdx] = 283.0 + (maxDepth_ - globalPos[1])*0.03; + values[temperatureIdx] = 283.0 + (aquiferDepth_ - globalPos[1])*0.03; if (globalPos[0] > 20 - eps_ && globalPos[0] < 30 + eps_ && globalPos[1] > 5 - eps_ && globalPos[1] < 35 + eps_) values[temperatureIdx] = 380; } private: - Scalar maxDepth_; - static constexpr Scalar eps_ = 1.5e-7; - std::string name_; + 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 }; } //end namespace -- GitLab From b3ac2d0adad5074dcd42b095c03de53b3276dd82 Mon Sep 17 00:00:00 2001 From: Katharina Heck Date: Fri, 22 Sep 2017 16:34:21 +0200 Subject: [PATCH 35/42] [fix] make referenceelement work with older dune version as well --- dumux/implicit/model.hh | 8 +++++++- dumux/porousmediumflow/implicit/velocityoutput.hh | 8 +++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/dumux/implicit/model.hh b/dumux/implicit/model.hh index b6759fdac3..c8c531c91f 100644 --- a/dumux/implicit/model.hh +++ b/dumux/implicit/model.hh @@ -31,6 +31,8 @@ #include #include +#include + namespace Dumux { @@ -958,8 +960,12 @@ protected: for (const auto& element : elements(gridView_())) { Dune::GeometryType geomType = element.geometry().type(); - const auto refElement = ReferenceElements::general(geomType); +#if DUNE_VERSION_NEWER(DUNE_COMMON,2,6) + const auto refElement = ReferenceElements::general(geomType); +#else + const auto &refElement = ReferenceElements::general(geomType); +#endif for (const auto& intersection : intersections(gridView_(), element)) { if (intersection.boundary()) { if (isBox) diff --git a/dumux/porousmediumflow/implicit/velocityoutput.hh b/dumux/porousmediumflow/implicit/velocityoutput.hh index 851f666c4e..74111d15cf 100644 --- a/dumux/porousmediumflow/implicit/velocityoutput.hh +++ b/dumux/porousmediumflow/implicit/velocityoutput.hh @@ -31,6 +31,8 @@ #include #include +#include + namespace Dumux { @@ -144,7 +146,11 @@ public: const auto geometry = element.geometry(); Dune::GeometryType geomType = geometry.type(); - const auto referenceElement = ReferenceElements::general(geomType); +#if DUNE_VERSION_NEWER(DUNE_COMMON,2,6) + const auto refElement = ReferenceElements::general(geomType); +#else + const auto &refElement = ReferenceElements::general(geomType); +#endif const Dune::FieldVector& localPos = referenceElement.position(0, 0); -- GitLab From 82d578ad0c0d6abba49608988ed9109b3d68cb47 Mon Sep 17 00:00:00 2001 From: Katharina Heck Date: Fri, 22 Sep 2017 17:21:31 +0200 Subject: [PATCH 36/42] [fix] adapt gridcreator to newest foamgrid version --- dumux/io/gridcreator.hh | 5 +++++ dumux/porousmediumflow/implicit/velocityoutput.hh | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/dumux/io/gridcreator.hh b/dumux/io/gridcreator.hh index 94f18994a7..c681a5d29b 100644 --- a/dumux/io/gridcreator.hh +++ b/dumux/io/gridcreator.hh @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -63,8 +64,12 @@ // FoamGrid specific includes #if HAVE_DUNE_FOAMGRID #include +#if DUNE_VERSION_NEWER(DUNE_COMMON,2,6) +#include +#else #include #endif +#endif #include #include diff --git a/dumux/porousmediumflow/implicit/velocityoutput.hh b/dumux/porousmediumflow/implicit/velocityoutput.hh index 74111d15cf..91c7226105 100644 --- a/dumux/porousmediumflow/implicit/velocityoutput.hh +++ b/dumux/porousmediumflow/implicit/velocityoutput.hh @@ -153,7 +153,7 @@ public: #endif const Dune::FieldVector& localPos - = referenceElement.position(0, 0); + = refElement.position(0, 0); // get the transposed Jacobian of the element mapping const typename Element::Geometry::JacobianTransposed jacobianT2 = -- GitLab From 3026601ffcb897e1b38d961cbbf955ee2b116e7b Mon Sep 17 00:00:00 2001 From: Katharina Heck Date: Fri, 22 Sep 2017 17:36:12 +0200 Subject: [PATCH 37/42] cleanup exercise 1 --- tutorial/ex1/README.md | 6 ++++++ tutorial/ex1/injection2pspatialparams.hh | 20 -------------------- 2 files changed, 6 insertions(+), 20 deletions(-) diff --git a/tutorial/ex1/README.md b/tutorial/ex1/README.md index a5757ce683..2c18721a16 100644 --- a/tutorial/ex1/README.md +++ b/tutorial/ex1/README.md @@ -48,6 +48,12 @@ make exercise1_2p exercise1_2p2c ./exercise1_2p2c exercise1.input ``` +* you can look at the results with paraview + +```bash +paraview injection-2p2c.pvd +``` +


### Task 3: Changing input parameters
diff --git a/tutorial/ex1/injection2pspatialparams.hh b/tutorial/ex1/injection2pspatialparams.hh index 95071e887b..f97ecab3f0 100644 --- a/tutorial/ex1/injection2pspatialparams.hh +++ b/tutorial/ex1/injection2pspatialparams.hh @@ -118,12 +118,6 @@ public: aquitardMaterialParams_.setLambda(2.0); aquiferMaterialParams_.setLambda(2.0); - // plot the material laws using gnuplot and exit - if (GET_RUNTIME_PARAM(TypeTag, bool, Problem.OnlyPlotMaterialLaws)) - { - plotMaterialLaws(); - exit(0); - } } /*! @@ -231,20 +225,6 @@ public: // return lambdaSolid_; // } - /*! - * \brief Creates a gnuplot output of the pc-Sw curve - */ - void plotMaterialLaws() - { - PlotMaterialLaw plotMaterialLaw; - GnuplotInterface gnuplot; - plotMaterialLaw.addpcswcurve(gnuplot, aquitardMaterialParams_, 0.2, 1.0, "upper layer (fine, aquitard)", "w lp"); - plotMaterialLaw.addpcswcurve(gnuplot, aquiferMaterialParams_, 0.2, 1.0, "lower layer (coarse, aquifer)", "w l"); - gnuplot.setOption("set xrange [0:1]"); - gnuplot.setOption("set label \"residual\\nsaturation\" at 0.1,100000 center"); - gnuplot.plot("pc-Sw"); - } - private: static constexpr Scalar eps_ = 1e-6; -- GitLab From 9a96022007225558b7c8f92e8e0f5c30470e4e1a Mon Sep 17 00:00:00 2001 From: Timo Koch Date: Tue, 10 Oct 2017 14:39:28 +0200 Subject: [PATCH 38/42] [tutorial] Correct permissions --- tutorial/ex1/exercise1_2p.cc | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 tutorial/ex1/exercise1_2p.cc diff --git a/tutorial/ex1/exercise1_2p.cc b/tutorial/ex1/exercise1_2p.cc old mode 100755 new mode 100644 -- GitLab From cd2f25830424e4a4e5d88de1c789dc3d7d576d32 Mon Sep 17 00:00:00 2001 From: Timo Koch Date: Tue, 10 Oct 2017 14:47:27 +0200 Subject: [PATCH 39/42] [tutorial] Change permissions --- tutorial/ex1/exercise1.input | 0 tutorial/ex2/exercise2.input | 0 2 files changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 tutorial/ex1/exercise1.input mode change 100755 => 100644 tutorial/ex2/exercise2.input diff --git a/tutorial/ex1/exercise1.input b/tutorial/ex1/exercise1.input old mode 100755 new mode 100644 diff --git a/tutorial/ex2/exercise2.input b/tutorial/ex2/exercise2.input old mode 100755 new mode 100644 -- GitLab From 28ee18c9e51454ee0ae157c0cec47d2249427eae Mon Sep 17 00:00:00 2001 From: Timo Koch Date: Tue, 10 Oct 2017 16:06:30 +0200 Subject: [PATCH 40/42] [doc] Fix handbook after moving impl/seq tutorial --- doc/handbook/3_tutorialimplicit.tex | 24 +++++++++++----------- doc/handbook/3_tutorialsequential.tex | 29 +++++++++++++-------------- doc/handbook/CMakeLists.txt | 16 +++++++-------- 3 files changed, 34 insertions(+), 35 deletions(-) diff --git a/doc/handbook/3_tutorialimplicit.tex b/doc/handbook/3_tutorialimplicit.tex index f908bceec9..387871652d 100644 --- a/doc/handbook/3_tutorialimplicit.tex +++ b/doc/handbook/3_tutorialimplicit.tex @@ -65,12 +65,12 @@ The solved equations are the mass balances of water and oil: \subsection{The Main File} Listing \ref{tutorial-implicit:mainfile} shows the main application file -\texttt{tutorial/tutorial\_implicit.cc} for the implicit two-phase +\texttt{tutorial/tutorial\_implicit/tutorial\_implicit.cc} for the implicit two-phase model. This file has to be compiled and executed in order to solve the problem described above. -\begin{lst}[File tutorial/tutorial\_implicit.cc]\label{tutorial-implicit:mainfile} \mbox{} - \lstinputlisting[style=DumuxCode, numbersep=5pt, firstline=24, firstnumber=24]{../../tutorial/tutorial_implicit.cc} +\begin{lst}[File tutorial/tutorial\_implicit/tutorial\_implicit.cc]\label{tutorial-implicit:mainfile} \mbox{} + \lstinputlisting[style=DumuxCode, numbersep=5pt, firstline=24, firstnumber=24]{../../tutorial/tutorial_implicit/tutorial_implicit.cc} \end{lst} From line \ref{tutorial-implicit:include-begin} to line @@ -99,8 +99,8 @@ values provided in the command line have precedence. Listing~\ref{tutorial-implicit:parameter-file} shows the default parameter file for the tutorial problem. -\begin{lst}[File tutorial/tutorial\_implicit.input]\label{tutorial-implicit:parameter-file} \mbox{} -\lstinputlisting[style=DumuxParameterFile]{../../tutorial/tutorial_implicit.input} +\begin{lst}[File tutorial/tutorial\_implicit/tutorial\_implicit.input]\label{tutorial-implicit:parameter-file} \mbox{} +\lstinputlisting[style=DumuxParameterFile]{../../tutorial/tutorial_implicit/tutorial_implicit.input} \end{lst} To provide an error message, the usage message which is displayed to @@ -116,8 +116,8 @@ When solving a problem using \Dumux, the most important file is the so-called \textit{problem file} as shown in listing~\ref{tutorial-implicit:problemfile}. -\begin{lst}[File tutorial/tutorialproblem\_implicit.hh]\label{tutorial-implicit:problemfile} \mbox{} -\lstinputlisting[style=DumuxCode, numbersep=5pt, firstline=24, firstnumber=24]{../../tutorial/tutorialproblem_implicit.hh} +\begin{lst}[File tutorial/tutorial\_implicit/tutorialproblem\_implicit.hh]\label{tutorial-implicit:problemfile} \mbox{} +\lstinputlisting[style=DumuxCode, numbersep=5pt, firstline=24, firstnumber=24]{../../tutorial/tutorial_implicit/tutorialproblem_implicit.hh} \end{lst} First, a new type tag is created for the problem in line @@ -247,7 +247,7 @@ interactions such as solubility effects come into play and properties of mixtures such as density or enthalpy are of interest. These interactions are defined by {\em fluid systems}, which are located in \verb+dumux/material/fluidsystems+. A more thorough overview of the -\Dumux fluid framework can be found +\Dumux fluid framework can be found at \url{http://www.dumux.org/doxygen-stable/html-\DumuxVersion/modules.php} %in chapter~\ref{sec:fluidframework}. @@ -270,8 +270,8 @@ should be derived from the base class \ref{tutorial-implicit:spatialparametersfile} shows the file \\ \verb+tutorialspatialparams_implicit.hh+: -\begin{lst}[File tutorial/tutorialspatialparams\_implicit.hh]\label{tutorial-implicit:spatialparametersfile} \mbox{} -\lstinputlisting[style=DumuxCode, numbersep=5pt, firstline=25, firstnumber=25]{../../tutorial/tutorialspatialparams_implicit.hh} +\begin{lst}[File tutorial/tutorial\_implicit/tutorialspatialparams\_implicit.hh]\label{tutorial-implicit:spatialparametersfile} \mbox{} +\lstinputlisting[style=DumuxCode, numbersep=5pt, firstline=25, firstnumber=25]{../../tutorial/tutorial_implicit/tutorialspatialparams_implicit.hh} \end{lst} First, the spatial parameters type tag is created on line @@ -411,7 +411,7 @@ To do that, you have to select different components via the property system in t \end{enumerate} If you want to take a closer look on how the fluid classes are defined and which substances are already available please browse through the files in the directory -\texttt{/dumux/material/components} and read +\texttt{/dumux/material/components} and read the doxygen documentation \url{http://www.dumux.org/doxygen-stable/html-\DumuxVersion/modules.php}. %chapter~\ref{sec:fluidframework}. @@ -597,7 +597,7 @@ As you have experienced, compilation takes quite some time. Therefore, via \textit{parameter input files}. In the code, parameters can be read via the macro -\texttt{GET\_RUNTIME\_PARAM(TypeTag, Scalar, +\texttt{GET\_RUNTIME\_PARAM(TypeTag, Scalar, MyWonderful\allowbreak Group.MyWonderfulParameter);}. In this exercise we will explore the possibilities of the parameter file. For this we take a look at the file \texttt{ex3\_tutorial\_implicit.input} in the \texttt{solutions\_implicit} folder. Besides the parameters which you already used in the parameter file above, diff --git a/doc/handbook/3_tutorialsequential.tex b/doc/handbook/3_tutorialsequential.tex index e2d8754671..228ddb3bc9 100644 --- a/doc/handbook/3_tutorialsequential.tex +++ b/doc/handbook/3_tutorialsequential.tex @@ -57,8 +57,8 @@ executed, has to be set up, if the problem described above is to be solved using a sequential model. This main file can be found in the directory \texttt{/tutorial} of the stable part of \Dumux. -\begin{lst}[File tutorial/tutorial\_sequential.cc]\label{tutorial-sequential:mainfile} \mbox{} -\lstinputlisting[style=DumuxCode, numbersep=5pt, firstline=24, firstnumber=24]{../../tutorial/tutorial_sequential.cc} +\begin{lst}[File tutorial/tutorial\_sequential/tutorial\_sequential.cc]\label{tutorial-sequential:mainfile} \mbox{} +\lstinputlisting[style=DumuxCode, numbersep=5pt, firstline=24, firstnumber=24]{../../tutorial/tutorial_sequential/tutorial_sequential.cc} \end{lst} First, from line \ref{tutorial-sequential:include-begin} to line @@ -85,8 +85,8 @@ values provided in the command line have precedence. Listing~\ref{tutorial-sequential:parameter-file} shows the default parameter file for the tutorial problem. -\begin{lst}[File tutorial/tutorial\_sequential.input]\label{tutorial-sequential:parameter-file} \mbox{} -\lstinputlisting[style=DumuxParameterFile]{../../tutorial/tutorial_sequential.input} +\begin{lst}[File tutorial/tutorial\_sequential/tutorial\_sequential.input]\label{tutorial-sequential:parameter-file} \mbox{} +\lstinputlisting[style=DumuxParameterFile]{../../tutorial/tutorial_sequential/tutorial_sequential.input} \end{lst} To provide an error message, the usage message which is displayed to @@ -104,8 +104,8 @@ so-called \textit{problem file} as shown in listing \ref{tutorial-sequential:problemfile} of \texttt{tutorialproblem\_sequential.hh}. -\begin{lst}[File tutorial/tutorialproblem\_sequential.hh]\label{tutorial-sequential:problemfile} \mbox{} -\lstinputlisting[style=DumuxCode, numbersep=5pt, firstline=24, firstnumber=24]{../../tutorial/tutorialproblem_sequential.hh} +\begin{lst}[File tutorial/tutorial\_sequential/tutorialproblem\_sequential.hh]\label{tutorial-sequential:problemfile} \mbox{} +\lstinputlisting[style=DumuxCode, numbersep=5pt, firstline=24, firstnumber=24]{../../tutorial/tutorial_sequential/tutorialproblem_sequential.hh} \end{lst} First, both \Dune grid handlers and the sequential model of \Dumux @@ -189,8 +189,8 @@ on the functions, consult the documentation in the code. Listing \ref{tutorial-sequential:spatialparamsfile} shows the file \verb+tutorialspatialparams_sequential.hh+: -\begin{lst}[File tutorial/tutorialspatialparams\_sequential.hh]\label{tutorial-sequential:spatialparamsfile} \mbox{} -\lstinputlisting[style=DumuxCode, numbersep=5pt, firstline=24, firstnumber=24]{../../tutorial/tutorialspatialparams_sequential.hh} +\begin{lst}[File tutorial/tutorial\_sequential/tutorialspatialparams\_sequential.hh]\label{tutorial-sequential:spatialparamsfile} \mbox{} +\lstinputlisting[style=DumuxCode, numbersep=5pt, firstline=24, firstnumber=24]{../../tutorial/tutorial_sequential/tutorialspatialparams_sequential.hh} \end{lst} As this file only slightly differs from the implicit version, consult chapter \ref{tutorial-implicit:description-spatialParameters} for explanations. @@ -211,18 +211,18 @@ For Exercise 1 you only have to make some small changes in the tutorial files. \item \textbf{Altering output} To get an impression what the results should look like you can first run the -original version of the sequential tutorial model by typing \texttt{./tutorial\_sequential}. +original version of the sequential tutorial model by typing \texttt{./tutorial/tutorial\_sequential/tutorial\_sequential}. The runtime parameters which are set can be found in the input file (listing~\ref{tutorial-sequential:parameter-file}). -If the input file has the same name than the main file (e.g. \texttt{tutorial\_sequential.cc} -and \texttt{tutorial\_sequential.input}), it is automatically chosen. If the name differs -the program has to be started typing \texttt{./tutorial\_sequential -parameterFile .input}. -For more options you can also type \texttt{./tutorial\_sequential -h}. For the +If the input file has the same name than the main file (e.g. \texttt{tutorial/tutorial\_sequential/tutorial\_sequential.cc} +and \texttt{tutorial/tutorial\_sequential/tutorial\_sequential.input}), it is automatically chosen. If the name differs +the program has to be started typing \texttt{./tutorial/tutorial\_sequential/tutorial\_sequential -parameterFile .input}. +For more options you can also type \texttt{./tutorial/tutorial\_sequential/tutorial\_sequential -h}. For the visualisation with paraview please refer to \ref{quick-start-guide}.\\ As you can see, the simulation creates many output files. To reduce these in order to perform longer simulations, change the method responsible for output (line \ref{tutorial-sequential:outputinterval} in the file \texttt{tutorialproblem\_\allowbreak sequential}) as to write an output only every 20 time-steps. Compile the main file by typing -\texttt{make tutorial\_sequential} and run the model. Now, run the simulation for 5e5 seconds. +\texttt{make tutorial/tutorial\_sequential/tutorial\_sequential} and run the model. Now, run the simulation for 5e5 seconds. \item \textbf{Changing the Model Domain and the Boundary Conditions} \\ Change the size of the model domain so that you get a rectangle @@ -527,4 +527,3 @@ so both models can also work with functions based ond \mbox{\texttt{...AtPos(Glo no matter if we model implicit or sequential. Try to formulate a spatial parameters file that works with both problems, the implicit and the sequential. Therein, only use functions at the position. - diff --git a/doc/handbook/CMakeLists.txt b/doc/handbook/CMakeLists.txt index f2f89dcb57..e19249dee1 100644 --- a/doc/handbook/CMakeLists.txt +++ b/doc/handbook/CMakeLists.txt @@ -22,14 +22,14 @@ set(TEX_INPUTS 5_models.tex 5_propertysystem.tex 5_spatialdiscretizations.tex - ../../tutorial/tutorial_implicit.cc - ../../tutorial/tutorial_implicit.input - ../../tutorial/tutorialproblem_implicit.hh - ../../tutorial/tutorialspatialparams_implicit.hh - ../../tutorial/tutorial_sequential.cc - ../../tutorial/tutorial_sequential.input - ../../tutorial/tutorialproblem_sequential.hh - ../../tutorial/tutorialspatialparams_sequential.hh) + ../../tutorial/tutorial_implicit/tutorial_implicit.cc + ../../tutorial/tutorial_implicit/tutorial_implicit.input + ../../tutorial/tutorial_implicit/tutorialproblem_implicit.hh + ../../tutorial/tutorial_implicit/tutorialspatialparams_implicit.hh + ../../tutorial/tutorial_sequential/tutorial_sequential.cc + ../../tutorial/tutorial_sequential/tutorial_sequential.input + ../../tutorial/tutorial_sequential/tutorialproblem_sequential.hh + ../../tutorial/tutorial_sequential/tutorialspatialparams_sequential.hh) set(TEX_IMAGES PNG/box_disc.png -- GitLab From e6addfeb650207d92c9d1cce8efa63996d6d9a95 Mon Sep 17 00:00:00 2001 From: Timo Koch Date: Tue, 10 Oct 2017 16:14:21 +0200 Subject: [PATCH 41/42] Update README.md ex1 --- tutorial/ex1/README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tutorial/ex1/README.md b/tutorial/ex1/README.md index 2c18721a16..ca823871d5 100644 --- a/tutorial/ex1/README.md +++ b/tutorial/ex1/README.md @@ -5,11 +5,11 @@ N2 is injected in an aquifer previously saturated with water with an injection rate of 0.001 kg/(s*m$`^2`$). The aquifer is situated 2700 m below see level and the domain size is 60 m x 40 m. It consists of two layers, a moderately permeable one ($`\Omega_1`$) and a lower permeable one ($`\Omega_2`$). - + ## Preparing the exercise -* Navigate to the directory `dumux/tutorial/dumux-course` +* Navigate to the directory `dumux/tutorial/ex1` _Exercise 1_ deals with two problems: a two-phase immiscible problem (__2p__) and a two-phase compositional problem (__2p2c__). They both set up the same scenario with the difference that the 2p2c assumes a miscible fluid state for the two fluids (water and gaseous N2) and the 2p model assumes an immiscible fluid state. @@ -32,7 +32,7 @@ Locate all the files you will need for this exercise * Change to the build-directory ```bash -cd build-cmake/tutorial/exercise1 +cd ../../build-cmake/tutorial/exercise1 ``` * Compile both executables `exercise1_2p` and `exercise1_2p2c` @@ -147,6 +147,6 @@ make injection2pniproblem # builds new executable __Initial conditions:__ The same temperature gradient as in the boundary conditions with an additional lens (with position: 20 < x < 30, 5 < y < 35), which has an initial temperature of 380 K. - + The non-isothermal model requires additional spatial parameters like the thermal conductivity. They are already implemented in `injection2pspatialparams.hh`, you just need to _uncomment_ them. -- GitLab From d6954c47d5df63332c7e05af127188835c820a12 Mon Sep 17 00:00:00 2001 From: Timo Koch Date: Tue, 10 Oct 2017 16:15:00 +0200 Subject: [PATCH 42/42] Update README.md ex2 --- tutorial/ex2/README.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/tutorial/ex2/README.md b/tutorial/ex2/README.md index dca532eb27..5473aaba6b 100644 --- a/tutorial/ex2/README.md +++ b/tutorial/ex2/README.md @@ -6,7 +6,7 @@ The problem setup is identical to the previous [_exercise 1_](../ex1/README.md). ## Preparing the exercise -* Navigate to the directory `dumux/tutorial/dumux-course` +* Navigate to the directory `dumux/tutorial/ex2` _Exercise 2_ deals with a two-phase compositional problem (__2p2c__). Goal is to learn how to use compile and runtime parameters and the _DuMuX property system_. @@ -17,7 +17,7 @@ _Exercise 2_ deals with a two-phase compositional problem (__2p2c__). Goal is to Locate all the files you will need for this exercise * The __main file__: `exercise2.cc` * The __problem file__: `injection2p2cproblem.hh` -* The __spatial parameters file__: `injection2pspatialparams.hh` +* The __spatial parameters file__: `injection2p2cspatialparams.hh` * The __input file__: `exercise2.input` * Two header files containing: * a custom __local residual__ in: `mylocalresidual.hh` @@ -31,7 +31,7 @@ Locate all the files you will need for this exercise * Change to the build-directory ```bash -cd build-cmake/tutorial/exercise2 +cd ../../build-cmake/tutorial/exercise2 ``` * Compile the executable `exercise2` @@ -44,7 +44,6 @@ make exercise2 ```bash ./exercise2 -paraview *pvd ``` Note: Because the input file has the same name as the executable, DuMuX will find it automatically. -- GitLab