// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- // vi: set et ts=4 sw=4 sts=4: /* This file is part of the Open Porous Media project (OPM). OPM 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. OPM 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 OPM. If not, see . Consult the COPYING file in the top-level source directory of this module for the precise wording of the license and the list of copyright holders. */ /*! * \file * * \copydoc Opm::Tutorial1Problem */ #ifndef EWOMS_TUTORIAL1_PROBLEM_HH /*@\label{tutorial1:guardian1}@*/ #define EWOMS_TUTORIAL1_PROBLEM_HH /*@\label{tutorial1:guardian2}@*/ // The numerical model #include // The spatial discretization (VCFV == Vertex-Centered Finite Volumes) #include /*@\label{tutorial1:include-discretization}@*/ // The chemical species that are used #include #include // Headers required for the capillary pressure law #include /*@\label{tutorial1:rawLawInclude}@*/ #include #include // For the DUNE grid #include /*@\label{tutorial1:include-grid-manager}@*/ #include /*@\label{tutorial1:include-grid-manager}@*/ // For Dune::FieldMatrix #include #include namespace Opm { // forward declaration of the problem class template class Tutorial1Problem; } namespace Opm::Properties { // Create a new type tag for the problem // Create new type tags namespace TTag { struct Tutorial1Problem { using InheritsFrom = std::tuple; }; } // end namespace TTag // Select the vertex centered finite volume method as spatial discretization template struct SpatialDiscretizationSplice { using type = TTag::VcfvDiscretization; }; /*@\label{tutorial1:set-spatial-discretization}@*/ // Set the "Problem" property template struct Problem { using type = Opm::Tutorial1Problem; }; /*@\label{tutorial1:set-problem}@*/ // Set grid and the grid manager to be used template struct Grid { using type = Dune::YaspGrid; }; /*@\label{tutorial1:set-grid}@*/ template struct Vanguard { using type = Opm::CubeGridVanguard; }; /*@\label{tutorial1:set-grid-manager}@*/ // Set the wetting phase /*@\label{tutorial1:2p-system-start}@*/ template struct WettingPhase /*@\label{tutorial1:wettingPhase}@*/ { using Scalar = GetPropType; using type = Opm::LiquidPhase >; }; // Set the non-wetting phase template struct NonwettingPhase /*@\label{tutorial1:nonwettingPhase}@*/ { using Scalar = GetPropType; using type = Opm::LiquidPhase >; }; /*@\label{tutorial1:2p-system-end}@*/ // Set the material law template struct MaterialLaw { private: // create a class holding the necessary information for a // two-phase capillary pressure law using Scalar = GetPropType; using FluidSystem = GetPropType; enum { wettingPhaseIdx = FluidSystem::wettingPhaseIdx }; enum { nonWettingPhaseIdx = FluidSystem::nonWettingPhaseIdx }; using Traits = Opm::TwoPhaseMaterialTraits; // define the material law which is parameterized by effective // saturations using RawMaterialLaw = Opm::RegularizedBrooksCorey; /*@\label{tutorial1:rawlaw}@*/ public: // Convert absolute saturations into effective ones before passing // it to the base capillary pressure law using type = Opm::EffToAbsLaw; /*@\label{tutorial1:eff2abs}@*/ }; } // namespace Opm::Properties namespace Opm { //! Tutorial problem using the "immiscible" model. template class Tutorial1Problem : public GetPropType /*@\label{tutorial1:def-problem}@*/ { using ParentType = GetPropType; using Scalar = GetPropType; using GridView = GetPropType; // Grid dimension enum { dim = GridView::dimension, dimWorld = GridView::dimensionworld }; // The type of the intrinsic permeability tensor using DimMatrix = Dune::FieldMatrix; // eWoms specific types are specified via the property system using Simulator = GetPropType; using PrimaryVariables = GetPropType; using RateVector = GetPropType; using BoundaryRateVector = GetPropType; using FluidSystem = GetPropType; using Indices = GetPropType; using MaterialLaw = GetPropType; using MaterialLawParams = GetPropType; /*@\label{tutorial1:matLawObjectType}@*/ // phase indices enum { numPhases = FluidSystem::numPhases }; enum { wettingPhaseIdx = FluidSystem::wettingPhaseIdx }; enum { nonWettingPhaseIdx = FluidSystem::nonWettingPhaseIdx }; // Indices of the conservation equations enum { contiWettingEqIdx = Indices::conti0EqIdx + wettingPhaseIdx }; enum { contiNonWettingEqIdx = Indices::conti0EqIdx + nonWettingPhaseIdx }; public: //! The constructor of the problem. This only _allocates_ the memory required by the //! problem. The constructor is supposed to _never ever_ throw an exception. Tutorial1Problem(Simulator& simulator) : ParentType(simulator) , eps_(3e-6) { } //! This method initializes the data structures allocated by the problem //! constructor. In contrast to the constructor, exceptions thrown from within this //! method won't lead to segmentation faults. void finishInit() { ParentType::finishInit(); // Use an isotropic and homogeneous intrinsic permeability K_ = this->toDimMatrix_(1e-7); // Parameters of the Brooks-Corey law materialParams_.setEntryPressure(500.0 /*Pa*/); /*@\label{tutorial1:setLawParams}@*/ materialParams_.setLambda(2); // shape parameter // Set the residual saturations materialParams_.setResidualSaturation(wettingPhaseIdx, 0.0); materialParams_.setResidualSaturation(nonWettingPhaseIdx, 0.0); // wrap up the initialization of the material law's parameters materialParams_.finalize(); } /*! * \copydoc FvBaseMultiPhaseProblem::registerParameters */ static void registerParameters() { ParentType::registerParameters(); Parameters::SetDefault(100); Parameters::SetDefault(1); Parameters::SetDefault>(300.0); Parameters::SetDefault>(60.0); if constexpr (dim == 3) { Parameters::SetDefault(1); Parameters::SetDefault>(0.0); } Parameters::SetDefault>(100e3); Parameters::SetDefault>(125.0); } //! Specifies the problem name. This is used for files generated by the simulation. std::string name() const { return "tutorial1"; } //! Returns the temperature at a given position. template Scalar temperature(const Context& /*context*/, unsigned /*spaceIdx*/, unsigned /*timeIdx*/) const { return 283.15; } //! Returns the intrinsic permeability tensor [m^2] at a position. template const DimMatrix& intrinsicPermeability(const Context& /*context*/, /*@\label{tutorial1:permeability}@*/ unsigned /*spaceIdx*/, unsigned /*timeIdx*/) const { return K_; } //! Defines the porosity [-] of the medium at a given position template Scalar porosity(const Context& /*context*/, unsigned /*spaceIdx*/, unsigned /*timeIdx*/) const /*@\label{tutorial1:porosity}@*/ { return 0.2; } //! Returns the parameter object for the material law at a given position template const MaterialLawParams& materialLawParams(const Context& /*context*/, /*@\label{tutorial1:matLawParams}@*/ unsigned /*spaceIdx*/, unsigned /*timeIdx*/) const { return materialParams_; } //! Evaluates the boundary conditions. template void boundary(BoundaryRateVector& values, const Context& context, unsigned spaceIdx, unsigned timeIdx) const { const auto& pos = context.pos(spaceIdx, timeIdx); if (pos[0] < eps_) { // Free-flow conditions on left boundary const auto& materialParams = this->materialLawParams(context, spaceIdx, timeIdx); Opm::ImmiscibleFluidState fs; Scalar Sw = 1.0; fs.setSaturation(wettingPhaseIdx, Sw); fs.setSaturation(nonWettingPhaseIdx, 1.0 - Sw); fs.setTemperature(temperature(context, spaceIdx, timeIdx)); Scalar pC[numPhases]; MaterialLaw::capillaryPressures(pC, materialParams, fs); fs.setPressure(wettingPhaseIdx, 200e3); fs.setPressure(nonWettingPhaseIdx, 200e3 + pC[nonWettingPhaseIdx] - pC[nonWettingPhaseIdx]); typename FluidSystem::template ParameterCache paramCache; paramCache.updateAll(fs); for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++ phaseIdx) { fs.setDensity(phaseIdx, FluidSystem::density(fs, paramCache, phaseIdx)); fs.setViscosity(phaseIdx, FluidSystem::viscosity(fs, paramCache, phaseIdx)); } values.setFreeFlow(context, spaceIdx, timeIdx, fs); } else if (pos[0] > this->boundingBoxMax()[0] - eps_) { // forced outflow at the right boundary RateVector massRate(0.0); massRate[contiWettingEqIdx] = 0.0; // [kg / (s m^2)] massRate[contiNonWettingEqIdx] = 3e-2; // [kg / (s m^2)] values.setMassRate(massRate); } else // no flow at the remaining boundaries values.setNoFlow(); } //! Evaluates the source term for all conserved quantities at a given //! position of the domain [kg/(m^3 * s)]. Positive values mean that //! mass is created. template void source(RateVector& sourceRate, const Context& /*context*/, unsigned /*spaceIdx*/, unsigned /*timeIdx*/) const { sourceRate[contiWettingEqIdx] = 0.0; sourceRate[contiNonWettingEqIdx] = 0.0; } //! Evaluates the initial value at a given position in the domain. template void initial(PrimaryVariables& values, const Context& context, unsigned spaceIdx, unsigned timeIdx) const { Opm::ImmiscibleFluidState fs; // the domain is initially fully saturated by LNAPL Scalar Sw = 0.0; fs.setSaturation(wettingPhaseIdx, Sw); fs.setSaturation(nonWettingPhaseIdx, 1.0 - Sw); // the temperature is given by the temperature() method fs.setTemperature(temperature(context, spaceIdx, timeIdx)); // set pressure of the wetting phase to 200 kPa = 2 bar Scalar pC[numPhases]; MaterialLaw::capillaryPressures(pC, materialLawParams(context, spaceIdx, timeIdx), fs); fs.setPressure(wettingPhaseIdx, 200e3); fs.setPressure(nonWettingPhaseIdx, 200e3 + pC[nonWettingPhaseIdx] - pC[nonWettingPhaseIdx]); values.assignNaive(fs); } private: DimMatrix K_; // Object that holds the parameters of required by the capillary pressure law. MaterialLawParams materialParams_; /*@\label{tutorial1:matParamsObject}@*/ // small epsilon value Scalar eps_; }; } // namespace Opm #endif