From 06beaace09f27ae939e048dade5990b8c7c917bc Mon Sep 17 00:00:00 2001 From: Timo Koch <timo.koch@iws.uni-stuttgart.de> Date: Thu, 27 Jul 2017 17:53:36 +0200 Subject: [PATCH] [fringe][tut] Improve example for fringe / infiltration richards / 2p --- tutorial/capillaryfringe/2pfringeproblem.hh | 54 ++++--- tutorial/capillaryfringe/CMakeLists.txt | 2 +- tutorial/capillaryfringe/fringe_2p.input | 14 -- .../capillaryfringe/fringe_richards.input | 14 -- .../capillaryfringe/fringespatialparams.hh | 139 +++++++++++++++--- .../capillaryfringe/richardsfringeproblem.hh | 57 ++++--- tutorial/capillaryfringe/soil.input | 42 ++++++ 7 files changed, 232 insertions(+), 90 deletions(-) delete mode 100644 tutorial/capillaryfringe/fringe_2p.input delete mode 100644 tutorial/capillaryfringe/fringe_richards.input create mode 100644 tutorial/capillaryfringe/soil.input diff --git a/tutorial/capillaryfringe/2pfringeproblem.hh b/tutorial/capillaryfringe/2pfringeproblem.hh index d6eb06e162..f02d97dbb9 100644 --- a/tutorial/capillaryfringe/2pfringeproblem.hh +++ b/tutorial/capillaryfringe/2pfringeproblem.hh @@ -142,7 +142,7 @@ public: TwoPFringeProblem(TimeManager &timeManager, const GridView &gridView) : ParentType(timeManager, gridView) { - name_ = GET_RUNTIME_PARAM_FROM_GROUP(TypeTag, std::string, Problem, Name); + name_ = GET_RUNTIME_PARAM_FROM_GROUP(TypeTag, std::string, Problem, Name) + "_2p"; } /*! @@ -195,6 +195,9 @@ public: bcTypes.setAllDirichlet(); else bcTypes.setAllNeumann(); + static const bool bottomDirichlet = GET_RUNTIME_PARAM_FROM_GROUP(TypeTag, bool, Problem, BottomDirichlet); + if (bottomDirichlet && onLowerBoundary_(globalPos)) + bcTypes.setAllDirichlet(); return bcTypes; } @@ -208,20 +211,23 @@ public: */ PrimaryVariables dirichletAtPos(const GlobalPosition &globalPos) const { - return initialAtPos(globalPos); - } + PrimaryVariables values(0.0); + if (onUpperBoundary_(globalPos)) + { + static const Scalar sw = GET_RUNTIME_PARAM_FROM_GROUP(TypeTag, Scalar, Problem, TopSaturation); + const Scalar pc = MaterialLaw::pc(this->spatialParams().materialLawParamsAtPos(globalPos), sw); + values[pwIdx] = nonWettingReferencePressure() - pc; + values[snIdx] = 1.0-sw; + } + else if(onLowerBoundary_(globalPos)) + { + static const Scalar sw = 1.0; + const Scalar pc = MaterialLaw::pc(this->spatialParams().materialLawParamsAtPos(globalPos), sw); + values[pwIdx] = nonWettingReferencePressure() - pc; + values[snIdx] = 0.0; - /*! - * \brief Evaluate the boundary conditions for a dirichlet - * boundary segment. - * - * \param globalPos The position for which the Dirichlet value is set - * - * For this method, the \a values parameter stores primary variables. - */ - PrimaryVariables neumannAtPos(const GlobalPosition &globalPos) const - { - return PrimaryVariables(0.0); + } + return values; } /*! @@ -239,23 +245,30 @@ public: */ PrimaryVariables initialAtPos(const GlobalPosition &globalPos) const { + static const Scalar levelFactor = GET_RUNTIME_PARAM_FROM_GROUP(TypeTag, Scalar, Problem, WaterLevelFactor); + static const Scalar swBottom = GET_RUNTIME_PARAM_FROM_GROUP(TypeTag, Scalar, Problem, SwBottomInitial); + static const Scalar swTop = GET_RUNTIME_PARAM_FROM_GROUP(TypeTag, Scalar, Problem, SwTopInitial); + PrimaryVariables values(0.0); - if (globalPos[1] > 0.5*(this->bBoxMax()[1] - this->bBoxMin()[1])) + if (globalPos[1] > levelFactor*(this->bBoxMax()[1] - this->bBoxMin()[1])) { - const Scalar sw = 0.05; + const Scalar sw = swTop; const Scalar pc = MaterialLaw::pc(this->spatialParams().materialLawParamsAtPos(globalPos), sw); values[pwIdx] = nonWettingReferencePressure() - pc; values[snIdx] = 1.0-sw; } else { - const Scalar sw = 1.0; + const Scalar sw = swBottom; const Scalar pc = MaterialLaw::pc(this->spatialParams().materialLawParamsAtPos(globalPos), sw); values[pwIdx] = nonWettingReferencePressure() - pc; values[snIdx] = 1.0-sw; } return values; - }; + } + + bool shouldWriteRestartFile() const + { return false; } // \} @@ -266,6 +279,11 @@ private: return globalPos[1] > this->bBoxMax()[1] - eps_; } + bool onLowerBoundary_(const GlobalPosition &globalPos) const + { + return globalPos[1] < this->bBoxMin()[1] + eps_; + } + static constexpr Scalar eps_ = 1.5e-7; GlobalPosition lensLowerLeft_; diff --git a/tutorial/capillaryfringe/CMakeLists.txt b/tutorial/capillaryfringe/CMakeLists.txt index deb451555e..aeefd0843b 100644 --- a/tutorial/capillaryfringe/CMakeLists.txt +++ b/tutorial/capillaryfringe/CMakeLists.txt @@ -1,3 +1,3 @@ -add_input_file_links() +dune_symlink_to_source_files(FILES soil.input) dune_add_test(SOURCES fringe_richards.cc) dune_add_test(SOURCES fringe_2p.cc) diff --git a/tutorial/capillaryfringe/fringe_2p.input b/tutorial/capillaryfringe/fringe_2p.input deleted file mode 100644 index 6e19e1f3a7..0000000000 --- a/tutorial/capillaryfringe/fringe_2p.input +++ /dev/null @@ -1,14 +0,0 @@ -[TimeManager] -DtInitial = 3600 # [s] -TEnd = 36000000 # [s] - -[Grid] -UpperRight = 2 2 -Cells = 1 100 - -[Problem] -Name = 2p_fringe -EnableGravity = true # enable gravity - -[Newton] -EnableChop = true # chop for better convergence diff --git a/tutorial/capillaryfringe/fringe_richards.input b/tutorial/capillaryfringe/fringe_richards.input deleted file mode 100644 index 0e6e4c5228..0000000000 --- a/tutorial/capillaryfringe/fringe_richards.input +++ /dev/null @@ -1,14 +0,0 @@ -[TimeManager] -DtInitial = 3600 # [s] -TEnd = 36000000 # [s] - -[Grid] -UpperRight = 2 2 -Cells = 1 100 - -[Problem] -Name = richards_fringe -EnableGravity = true # enable gravity - -[Newton] -EnableChop = true # chop for better convergence diff --git a/tutorial/capillaryfringe/fringespatialparams.hh b/tutorial/capillaryfringe/fringespatialparams.hh index f4a15dc476..187a257a72 100644 --- a/tutorial/capillaryfringe/fringespatialparams.hh +++ b/tutorial/capillaryfringe/fringespatialparams.hh @@ -19,24 +19,46 @@ /*! * \file * - * \brief spatial parameters for the RichardsLensProblem + * \brief spatial parameters for the TwoPTwoCTestProblem */ #ifndef DUMUX_FRINGE_SPATIAL_PARAMETERS_HH #define DUMUX_FRINGE_SPATIAL_PARAMETERS_HH #include <dumux/material/spatialparams/implicit.hh> #include <dumux/material/fluidmatrixinteractions/2p/regularizedvangenuchten.hh> +#include <dumux/material/fluidmatrixinteractions/2p/linearmaterial.hh> #include <dumux/material/fluidmatrixinteractions/2p/efftoabslaw.hh> -#include <dumux/porousmediumflow/richards/implicit/model.hh> - namespace Dumux { +template<class TypeTag> +class FringeSpatialParams; + +namespace Properties +{ +// The spatial parameters TypeTag +NEW_TYPE_TAG(FringeSpatialParams); + +// Set the spatial parameters +SET_TYPE_PROP(FringeSpatialParams, SpatialParams, FringeSpatialParams<TypeTag>); + +// Set the material law +SET_PROP(FringeSpatialParams, MaterialLaw) +{ +private: + // define the material law which is parameterized by effective + // saturations + using Scalar = typename GET_PROP_TYPE(TypeTag, Scalar); +public: + // define the material law parameterized by absolute saturations + using type = EffToAbsLaw<RegularizedVanGenuchten<Scalar>>; +}; +} // end namespace Properties /*! - * \ingroup RichardsModel + * \ingroup TwoPTwoCModel * \ingroup ImplicitTestProblems - * \brief The spatial parameters for the RichardsLensProblem + * \brief The spatial parameters for the TwoPTwoCTestProblem */ template<class TypeTag> class FringeSpatialParams : public ImplicitSpatialParams<TypeTag> @@ -68,18 +90,29 @@ public: FringeSpatialParams(const Problem& problem, const GridView& gridView) : ParentType(problem, gridView) { - // residual saturations - outerMaterialParams_.setSwr(0.05); - outerMaterialParams_.setSnr(0.0); - - // parameters for the Van Genuchten law - // alpha and n - outerMaterialParams_.setVgAlpha(0.0037); - outerMaterialParams_.setVgn(4.7); - outerMaterialParams_.setPcLowSw(0.001); - - outerK_ = 5e-12; + lensLowerLeft_ = GET_RUNTIME_PARAM(TypeTag, GlobalPosition, LensSpatialParams.LowerLeft); + lensUpperRight_ = GET_RUNTIME_PARAM(TypeTag, GlobalPosition, LensSpatialParams.UpperRight); + + // residual saturations and parameters for the Van Genuchten law + materialParams_.setSwr(GET_RUNTIME_PARAM(TypeTag, Scalar, SpatialParams.Swr)); + materialParams_.setSnr(GET_RUNTIME_PARAM(TypeTag, Scalar, SpatialParams.Snr)); + materialParams_.setVgAlpha(GET_RUNTIME_PARAM(TypeTag, Scalar, SpatialParams.VanGenAlpha)); + materialParams_.setVgn(GET_RUNTIME_PARAM(TypeTag, Scalar, SpatialParams.VanGenN)); + materialParams_.setPcLowSw(GET_RUNTIME_PARAM(TypeTag, Scalar, SpatialParams.RegThresholdSw)); + + // same for lens: residual saturations and parameters for the Van Genuchten law + materialParamsLens_.setSwr(GET_RUNTIME_PARAM(TypeTag, Scalar, LensSpatialParams.Swr)); + materialParamsLens_.setSnr(GET_RUNTIME_PARAM(TypeTag, Scalar, LensSpatialParams.Snr)); + materialParamsLens_.setVgAlpha(GET_RUNTIME_PARAM(TypeTag, Scalar, LensSpatialParams.VanGenAlpha)); + materialParamsLens_.setVgn(GET_RUNTIME_PARAM(TypeTag, Scalar, LensSpatialParams.VanGenN)); + materialParamsLens_.setPcLowSw(GET_RUNTIME_PARAM(TypeTag, Scalar, LensSpatialParams.RegThresholdSw)); + + permeability_ = GET_RUNTIME_PARAM(TypeTag, Scalar, SpatialParams.Permeability); + lensPermeability_ = GET_RUNTIME_PARAM(TypeTag, Scalar, LensSpatialParams.Permeability); + porosity_ = GET_RUNTIME_PARAM(TypeTag, Scalar, SpatialParams.Porosity); + lensPorosity_ = GET_RUNTIME_PARAM(TypeTag, Scalar, LensSpatialParams.Porosity); + hasLens_ = GET_RUNTIME_PARAM(TypeTag, bool, LensSpatialParams.HasLens); } /*! @@ -89,7 +122,11 @@ public: */ PermeabilityType permeabilityAtPos(const GlobalPosition& globalPos) const { - return outerK_; + if (isInLens_(globalPos)) + return lensPermeability_; + else + return permeability_; + } /*! @@ -98,27 +135,81 @@ public: * \param globalPos The global position where we evaluate */ Scalar porosityAtPos(const GlobalPosition& globalPos) const - { return 0.4; } + { + if (isInLens_(globalPos)) + return lensPorosity_; + else + return porosity_; + } /*! * \brief Returns the parameters for the material law at a given location * - * This method is not actually required by the Richards model, but provided - * for the convenience of the RichardsLensProblem + * This method is not actually required by the TwoPTwoC model, but provided + * for the convenience of the TwoPTwoCLensProblem * * \param globalPos A global coordinate vector */ const MaterialLawParams& materialLawParamsAtPos(const GlobalPosition &globalPos) const { - return outerMaterialParams_; + if (isInLens_(globalPos)) + return materialParamsLens_; + else + return materialParams_; } + /*! + * \brief Returns the heat capacity \f$[J / (kg K)]\f$ of the rock matrix. + * + * This is only required for non-isothermal models. + * + * \param globalPos The global position + */ + Scalar solidHeatCapacityAtPos(const GlobalPosition& globalPos) const + { return 1480; /*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 globalPos The global position + */ + Scalar solidDensityAtPos(const GlobalPosition& globalPos) const + { return 1600; /*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 globalPos The global position + */ + Scalar solidThermalConductivityAtPos(const GlobalPosition& globalPos) const + { return 2; } + private: + bool isInLens_(const GlobalPosition &globalPos) const + { + if(!hasLens_) return false; + + for (int i = 0; i < dimWorld; ++i) + if (globalPos[i] < lensLowerLeft_[i] - eps_ || globalPos[i] > lensUpperRight_[i] + eps_) + return false; + + return true; + } + static constexpr Scalar eps_ = 1e-7; + + MaterialLawParams materialParams_; + MaterialLawParams materialParamsLens_; + Scalar permeability_, lensPermeability_; + Scalar porosity_, lensPorosity_; - static constexpr Scalar eps_ = 1.5e-7; + GlobalPosition lensLowerLeft_; + GlobalPosition lensUpperRight_; - Scalar outerK_; - MaterialLawParams outerMaterialParams_; + bool hasLens_; }; } // end namespace Dumux diff --git a/tutorial/capillaryfringe/richardsfringeproblem.hh b/tutorial/capillaryfringe/richardsfringeproblem.hh index de03cba329..334bcc2fc9 100644 --- a/tutorial/capillaryfringe/richardsfringeproblem.hh +++ b/tutorial/capillaryfringe/richardsfringeproblem.hh @@ -130,7 +130,7 @@ public: RichardsFringeProblem(TimeManager &timeManager, const GridView &gridView) : ParentType(timeManager, gridView) { - name_ = GET_RUNTIME_PARAM_FROM_GROUP(TypeTag, std::string, Problem, Name); + name_ = GET_RUNTIME_PARAM_FROM_GROUP(TypeTag, std::string, Problem, Name) + "_richards"; } /*! @@ -183,6 +183,9 @@ public: bcTypes.setAllDirichlet(); else bcTypes.setAllNeumann(); + static const bool bottomDirichlet = GET_RUNTIME_PARAM_FROM_GROUP(TypeTag, bool, Problem, BottomDirichlet); + if (bottomDirichlet && onLowerBoundary_(globalPos)) + bcTypes.setAllDirichlet(); return bcTypes; } @@ -196,20 +199,22 @@ public: */ PrimaryVariables dirichletAtPos(const GlobalPosition &globalPos) const { - return initialAtPos(globalPos); - } - - /*! - * \brief Evaluate the boundary conditions for a dirichlet - * boundary segment. - * - * \param globalPos The position for which the Dirichlet value is set - * - * For this method, the \a values parameter stores primary variables. - */ - PrimaryVariables neumannAtPos(const GlobalPosition &globalPos) const - { - return PrimaryVariables(0.0); + PrimaryVariables values(0.0); + if (onUpperBoundary_(globalPos)) + { + static const Scalar sw = GET_RUNTIME_PARAM_FROM_GROUP(TypeTag, Scalar, Problem, TopSaturation); + const Scalar pc = MaterialLaw::pc(this->spatialParams().materialLawParamsAtPos(globalPos), sw); + values[pressureIdx] = nonWettingReferencePressure() - pc; + values.setState(Indices::bothPhases); + } + else if(onLowerBoundary_(globalPos)) + { + static const Scalar sw = 1.0; + const Scalar pc = MaterialLaw::pc(this->spatialParams().materialLawParamsAtPos(globalPos), sw); + values[pressureIdx] = nonWettingReferencePressure() - pc; + values.setState(Indices::bothPhases); + } + return values; } /*! @@ -227,21 +232,30 @@ public: */ PrimaryVariables initialAtPos(const GlobalPosition &globalPos) const { + static const Scalar levelFactor = GET_RUNTIME_PARAM_FROM_GROUP(TypeTag, Scalar, Problem, WaterLevelFactor); + static const Scalar swBottom = GET_RUNTIME_PARAM_FROM_GROUP(TypeTag, Scalar, Problem, SwBottomInitial); + static const Scalar swTop = GET_RUNTIME_PARAM_FROM_GROUP(TypeTag, Scalar, Problem, SwTopInitial); + PrimaryVariables values(0.0); - if (globalPos[1] > 0.5*(this->bBoxMax()[1] - this->bBoxMin()[1])) + if (globalPos[1] > levelFactor*(this->bBoxMax()[1] - this->bBoxMin()[1])) { - const Scalar sw = 0.05; + const Scalar sw = swTop; const Scalar pc = MaterialLaw::pc(this->spatialParams().materialLawParamsAtPos(globalPos), sw); values[pressureIdx] = nonWettingReferencePressure() - pc; + values.setState(Indices::bothPhases); } else { - const Scalar sw = 1.0; + const Scalar sw = swBottom; const Scalar pc = MaterialLaw::pc(this->spatialParams().materialLawParamsAtPos(globalPos), sw); values[pressureIdx] = nonWettingReferencePressure() - pc; + values.setState(Indices::bothPhases); } return values; - }; + } + + bool shouldWriteRestartFile() const + { return false; } // \} @@ -252,6 +266,11 @@ private: return globalPos[1] > this->bBoxMax()[1] - eps_; } + bool onLowerBoundary_(const GlobalPosition &globalPos) const + { + return globalPos[1] < this->bBoxMin()[1] + eps_; + } + static constexpr Scalar eps_ = 1.5e-7; GlobalPosition lensLowerLeft_; diff --git a/tutorial/capillaryfringe/soil.input b/tutorial/capillaryfringe/soil.input new file mode 100644 index 0000000000..106238a27f --- /dev/null +++ b/tutorial/capillaryfringe/soil.input @@ -0,0 +1,42 @@ +[TimeManager] +DtInitial = 600 # [s] +MaxTimeStepSize = 600 # [s] +TEnd = 36000 # [s] + +[Grid] +UpperRight = 2 2 +Cells = 1 100 + +[Problem] +Name = fringe +EnableGravity = true # enable gravity +UsePrimaryVariableSwitch = false +TopSaturation = 0.05 +SwBottomInitial = 1.0 +SwTopInitial = 0.05 +WaterLevelFactor = 0.5 +BottomDirichlet = true + +[SpatialParams] +Permeability = 2.57e-12 # [m^2] +Porosity = 0.3 +Swr = 0.05 +Snr = 0.0 +RegThresholdSw = 0.01 +VanGenAlpha = 5.8e-4 +VanGenN = 1.8 + +[LensSpatialParams] +HasLens = true +LowerLeft = 0.1 1.4 +UpperRight = 1.8 1.7 +Permeability = 2.57e-16 # [m^2] +Porosity = 0.03 +Swr = 0.1 +Snr = 0.0 +RegThresholdSw = 0.1 +VanGenAlpha = 0.008 #5.8e-4 +VanGenN = 1.68 #17.8 + +[Newton] +EnableChop = true # chop for better convergence -- GitLab