Line | Branch | Exec | Source |
---|---|---|---|
1 | // -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- | ||
2 | // vi: set et ts=4 sw=4 sts=4: | ||
3 | // | ||
4 | // SPDX-FileCopyrightInfo: Copyright © DuMux Project contributors, see AUTHORS.md in root folder | ||
5 | // SPDX-License-Identifier: GPL-3.0-or-later | ||
6 | // | ||
7 | /*! | ||
8 | * \file | ||
9 | * \ingroup MPNCTests | ||
10 | * \brief Problem where liquid water is injected which has to go | ||
11 | * around an obstacle with \f$10^3\f$ lower permeability. | ||
12 | * | ||
13 | * The water is injected by means of a Dirichlet condition on the lower | ||
14 | * right of the domain. | ||
15 | */ | ||
16 | #ifndef DUMUX_OBSTACLEPROBLEM_HH | ||
17 | #define DUMUX_OBSTACLEPROBLEM_HH | ||
18 | |||
19 | #include <dumux/common/properties.hh> | ||
20 | #include <dumux/common/parameters.hh> | ||
21 | #include <dumux/common/boundarytypes.hh> | ||
22 | #include <dumux/common/numeqvector.hh> | ||
23 | |||
24 | #include <dumux/porousmediumflow/problem.hh> | ||
25 | #include <dumux/porousmediumflow/mpnc/initialconditionhelper.hh> | ||
26 | |||
27 | namespace Dumux { | ||
28 | |||
29 | /*! | ||
30 | * \ingroup MPNCTests | ||
31 | * \brief Problem where liquid water is injected which has to go | ||
32 | * around an obstacle with \f$10^3\f$ lower permeability. | ||
33 | * | ||
34 | * The water is injected by means of a Dirichlet condition on the lower | ||
35 | * right of the domain. | ||
36 | * | ||
37 | * The domain is sized 60m times 40m and consists of two media, a | ||
38 | * moderately permeable soil (\f$ K_0=10e-12 m^2\f$) and an obstacle | ||
39 | * at \f$[10; 20]m \times [0; 35]m \f$ with a lower permeablility of | ||
40 | * \f$ K_1=K_0/1000\f$. | ||
41 | * | ||
42 | * Initially, the whole domain is filled with nitrogen, the temperature | ||
43 | * is \f$25\symbol{23}C\f$ in the whole domain. The gas pressure in the | ||
44 | * domain is 1 bar, except on the inlet (lower 10 meters of right hand | ||
45 | * boundary) where the pressure is 2 bar. | ||
46 | * | ||
47 | * The boundary is no-flow except on the lower 10 meters of the left | ||
48 | * and the right boundary which are Dirichlet conditions with the same | ||
49 | * values as the initial condition. | ||
50 | * | ||
51 | * This problem uses the \ref MPNCModel. | ||
52 | */ | ||
53 | template <class TypeTag> | ||
54 | class ObstacleProblem | ||
55 | : public PorousMediumFlowProblem<TypeTag> | ||
56 | { | ||
57 | using ParentType = PorousMediumFlowProblem<TypeTag>; | ||
58 | using Scalar = GetPropType<TypeTag, Properties::Scalar>; | ||
59 | using FluidSystem = GetPropType<TypeTag, Properties::FluidSystem>; | ||
60 | using BoundaryTypes = Dumux::BoundaryTypes<GetPropType<TypeTag, Properties::ModelTraits>::numEq()>; | ||
61 | using PrimaryVariables = GetPropType<TypeTag, Properties::PrimaryVariables>; | ||
62 | using NumEqVector = Dumux::NumEqVector<PrimaryVariables>; | ||
63 | using ElementVolumeVariables = typename GetPropType<TypeTag, Properties::GridVolumeVariables>::LocalView; | ||
64 | using FVElementGeometry = typename GetPropType<TypeTag, Properties::GridGeometry>::LocalView; | ||
65 | using SubControlVolume = typename FVElementGeometry::SubControlVolume; | ||
66 | using SubControlVolumeFace = typename FVElementGeometry::SubControlVolumeFace; | ||
67 | using GridView = typename GetPropType<TypeTag, Properties::GridGeometry>::GridView; | ||
68 | using Element = typename GridView::template Codim<0>::Entity; | ||
69 | using GridGeometry = GetPropType<TypeTag, Properties::GridGeometry>; | ||
70 | using FluidState = GetPropType<TypeTag, Properties::FluidState>; | ||
71 | |||
72 | using ModelTraits = GetPropType<TypeTag, Properties::ModelTraits>; | ||
73 | using Indices = typename ModelTraits::Indices; | ||
74 | |||
75 | enum { dimWorld = GridView::dimensionworld }; | ||
76 | enum { numPhases = ModelTraits::numFluidPhases() }; | ||
77 | enum { numComponents = ModelTraits::numFluidComponents() }; | ||
78 | enum { gasPhaseIdx = FluidSystem::gasPhaseIdx }; | ||
79 | enum { liquidPhaseIdx = FluidSystem::liquidPhaseIdx }; | ||
80 | enum { H2OIdx = FluidSystem::H2OIdx }; | ||
81 | enum { N2Idx = FluidSystem::N2Idx }; | ||
82 | enum { fug0Idx = Indices::fug0Idx }; | ||
83 | enum { s0Idx = Indices::s0Idx }; | ||
84 | enum { p0Idx = Indices::p0Idx }; | ||
85 | |||
86 | using GlobalPosition = typename SubControlVolume::GlobalPosition; | ||
87 | using PhaseVector = Dune::FieldVector<Scalar, numPhases>; | ||
88 | |||
89 | public: | ||
90 | 2 | ObstacleProblem(std::shared_ptr<const GridGeometry> gridGeometry) | |
91 |
7/20✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 2 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 2 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✓ Branch 13 taken 2 times.
✓ Branch 15 taken 2 times.
✗ Branch 16 not taken.
✓ Branch 18 taken 2 times.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
✗ Branch 26 not taken.
✗ Branch 27 not taken.
|
6 | : ParentType(gridGeometry) |
92 | { | ||
93 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | const auto temperature = getParam<Scalar>("SpatialParams.Temperature"); |
94 | |||
95 | // initialize the tables of the fluid system | ||
96 | 2 | Scalar Tmin = temperature - 1.0; | |
97 | 2 | Scalar Tmax = temperature + 1.0; | |
98 | 2 | int nT = 3; | |
99 | |||
100 | 2 | Scalar pmin = 1.0e5 * 0.75; | |
101 | 2 | Scalar pmax = 2.0e5 * 1.25; | |
102 | 2 | int np = 1000; | |
103 | |||
104 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | FluidSystem::init(Tmin, Tmax, nT, pmin, pmax, np); |
105 |
2/4✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 2 times.
|
2 | name_ = getParam<std::string>("Problem.Name"); |
106 | 2 | } | |
107 | |||
108 | /*! | ||
109 | * \name Problem parameters | ||
110 | */ | ||
111 | // \{ | ||
112 | |||
113 | /*! | ||
114 | * \brief Returns the problem name | ||
115 | * | ||
116 | * This is used as a prefix for files generated by the simulation. | ||
117 | */ | ||
118 | const std::string name() const | ||
119 |
2/6✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
2 | { return name_; } |
120 | |||
121 | // \} | ||
122 | |||
123 | /*! | ||
124 | * \name Boundary conditions | ||
125 | */ | ||
126 | // \{ | ||
127 | /*! | ||
128 | * \brief Specifies which kind of boundary condition should be | ||
129 | * used for which equation on a given boundary segment | ||
130 | * | ||
131 | * \param globalPos The global position | ||
132 | */ | ||
133 | 28308 | BoundaryTypes boundaryTypesAtPos(const GlobalPosition &globalPos) const | |
134 | { | ||
135 | 28308 | BoundaryTypes bcTypes; | |
136 | 55149 | if (onInlet_(globalPos) || onOutlet_(globalPos)) | |
137 | bcTypes.setAllDirichlet(); | ||
138 | else | ||
139 | bcTypes.setAllNeumann(); | ||
140 | 28308 | return bcTypes; | |
141 | } | ||
142 | |||
143 | /*! | ||
144 | * \brief Evaluates the boundary conditions for a Dirichlet boundary segment. | ||
145 | * | ||
146 | * \param globalPos The global position | ||
147 | */ | ||
148 | PrimaryVariables dirichletAtPos(const GlobalPosition &globalPos) const | ||
149 | { | ||
150 | 1134 | return initial_(globalPos); | |
151 | } | ||
152 | |||
153 | /*! | ||
154 | * \brief Evaluates the boundary conditions for a Neumann boundary segment. | ||
155 | */ | ||
156 | ✗ | NumEqVector neumannAtPos(const GlobalPosition& globalPos) const | |
157 | { | ||
158 |
1/2✓ Branch 0 taken 16200 times.
✗ Branch 1 not taken.
|
237080 | return NumEqVector(0.0); |
159 | } | ||
160 | |||
161 | // \} | ||
162 | |||
163 | /*! | ||
164 | * \name Volume terms | ||
165 | */ | ||
166 | // \{ | ||
167 | |||
168 | /*! | ||
169 | * \brief Evaluates the source term for all balance equations within a given | ||
170 | * sub-control volume. | ||
171 | * | ||
172 | * \param element The finite element | ||
173 | * \param fvGeometry The finite volume geometry of the element | ||
174 | * \param elemVolVars The volume variables of the element | ||
175 | * \param scv The sub-control volume | ||
176 | * | ||
177 | * Positive values mean that mass is created, negative ones mean that it vanishes. | ||
178 | */ | ||
179 | ✗ | NumEqVector source(const Element &element, | |
180 | const FVElementGeometry& fvGeometry, | ||
181 | const ElementVolumeVariables& elemVolVars, | ||
182 | const SubControlVolume &scv) const | ||
183 | { | ||
184 | 1209216 | return NumEqVector(0.0); | |
185 | } | ||
186 | |||
187 | /*! | ||
188 | * \brief Evaluates the initial value for a control volume. | ||
189 | * | ||
190 | * \param globalPos The center of the finite volume which ought to be set. | ||
191 | * | ||
192 | * For this method, the \a values parameter stores primary | ||
193 | * variables. | ||
194 | */ | ||
195 | PrimaryVariables initialAtPos(const GlobalPosition &globalPos) const | ||
196 | { | ||
197 | 809 | return initial_(globalPos); | |
198 | } | ||
199 | |||
200 | // \} | ||
201 | |||
202 | private: | ||
203 | // the internal method for the initial condition | ||
204 | 1943 | PrimaryVariables initial_(const GlobalPosition &globalPos) const | |
205 | { | ||
206 | int refPhaseIdx, otherPhaseIdx; | ||
207 | Scalar refPhasePressure, refPhaseSaturation; | ||
208 | |||
209 | 1943 | FluidState fs; | |
210 | 3886 | fs.setTemperature(this->spatialParams().temperatureAtPos(globalPos)); | |
211 | 3886 | if (onInlet_(globalPos)) | |
212 | { | ||
213 | // only liquid on inlet | ||
214 | 572 | refPhaseIdx = liquidPhaseIdx; | |
215 | 572 | otherPhaseIdx = gasPhaseIdx; | |
216 | 572 | refPhasePressure = 2e5; | |
217 | 572 | refPhaseSaturation = 1.0; | |
218 | |||
219 | 572 | fs.setSaturation(liquidPhaseIdx, refPhaseSaturation); | |
220 | 572 | fs.setPressure(liquidPhaseIdx, refPhasePressure); | |
221 | 572 | fs.setMoleFraction(liquidPhaseIdx, N2Idx, 0.0); | |
222 | 572 | fs.setMoleFraction(liquidPhaseIdx, H2OIdx, 1.0); | |
223 | } | ||
224 | else { | ||
225 | // elsewhere, only gas | ||
226 | 1371 | refPhaseIdx = gasPhaseIdx; | |
227 | 1371 | otherPhaseIdx = liquidPhaseIdx; | |
228 | 1371 | refPhasePressure = 1e5; | |
229 | 1371 | refPhaseSaturation = 1.0; | |
230 | |||
231 | 1371 | fs.setSaturation(gasPhaseIdx, refPhaseSaturation); | |
232 | 1371 | fs.setPressure(gasPhaseIdx, refPhasePressure); | |
233 | 1371 | fs.setMoleFraction(gasPhaseIdx, N2Idx, 0.99); | |
234 | 1371 | fs.setMoleFraction(gasPhaseIdx, H2OIdx, 0.01); | |
235 | } | ||
236 | |||
237 | 1943 | fs.setSaturation(otherPhaseIdx, 1.0 - refPhaseSaturation); | |
238 | 3886 | const auto fluidMatrixInteraction = this->spatialParams().fluidMatrixInteractionAtPos(globalPos); | |
239 | 1943 | const int wPhaseIdx = this->spatialParams().template wettingPhaseAtPos<FluidSystem>(globalPos); | |
240 | 1943 | const auto pc = fluidMatrixInteraction.capillaryPressures(fs, wPhaseIdx); | |
241 | 5829 | fs.setPressure(otherPhaseIdx, refPhasePressure + (pc[otherPhaseIdx] - pc[refPhaseIdx])); | |
242 | |||
243 | MPNCInitialConditionHelper<PrimaryVariables, FluidSystem, ModelTraits> helper; | ||
244 | 1943 | helper.solve(fs, MPNCInitialConditions::NotAllPhasesPresent{.refPhaseIdx = refPhaseIdx}); | |
245 | 1943 | return helper.getPrimaryVariables(fs); | |
246 | } | ||
247 | |||
248 | ✗ | bool onInlet_(const GlobalPosition &globalPos) const | |
249 | { | ||
250 |
6/6✓ Branch 0 taken 4320 times.
✓ Branch 1 taken 17280 times.
✓ Branch 2 taken 1376 times.
✓ Branch 3 taken 5332 times.
✓ Branch 4 taken 584 times.
✓ Branch 5 taken 1359 times.
|
30251 | Scalar x = globalPos[0]; |
251 |
6/6✓ Branch 0 taken 4320 times.
✓ Branch 1 taken 17280 times.
✓ Branch 2 taken 1376 times.
✓ Branch 3 taken 5332 times.
✓ Branch 4 taken 584 times.
✓ Branch 5 taken 1359 times.
|
30251 | Scalar y = globalPos[1]; |
252 |
12/12✓ Branch 0 taken 4320 times.
✓ Branch 1 taken 17280 times.
✓ Branch 2 taken 3240 times.
✓ Branch 3 taken 1080 times.
✓ Branch 4 taken 1376 times.
✓ Branch 5 taken 5332 times.
✓ Branch 6 taken 989 times.
✓ Branch 7 taken 387 times.
✓ Branch 8 taken 584 times.
✓ Branch 9 taken 1359 times.
✓ Branch 10 taken 572 times.
✓ Branch 11 taken 12 times.
|
30251 | return x >= 60 - eps_ && y <= 10 + eps_; |
253 | } | ||
254 | |||
255 | ✗ | bool onOutlet_(const GlobalPosition &globalPos) const | |
256 | { | ||
257 |
2/4✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 5696 times.
✓ Branch 3 taken 21145 times.
|
26841 | Scalar x = globalPos[0]; |
258 |
2/4✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 5696 times.
✓ Branch 3 taken 21145 times.
|
26841 | Scalar y = globalPos[1]; |
259 |
4/8✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 5696 times.
✓ Branch 5 taken 21145 times.
✓ Branch 6 taken 4229 times.
✓ Branch 7 taken 1467 times.
|
26841 | return x < eps_ && y <= 10 + eps_; |
260 | } | ||
261 | |||
262 | static constexpr Scalar eps_ = 1e-6; | ||
263 | std::string name_; | ||
264 | }; | ||
265 | } // end namespace Dumux | ||
266 | |||
267 | #endif | ||
268 |