GCC Code Coverage Report


Directory: ../../../builds/dumux-repositories/
File: /builds/dumux-repositories/dumux/test/porousmediumflow/3p/infiltration/problem.hh
Date: 2024-09-21 20:52:54
Exec Total Coverage
Lines: 54 55 98.2%
Functions: 8 10 80.0%
Branches: 91 134 67.9%

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 ThreePTests
10 * \brief Isothermal NAPL infiltration problem: LNAPL contaminates
11 * the unsaturated and the saturated groundwater zone.
12 */
13 #ifndef DUMUX_INFILTRATION_THREEP_PROBLEM_HH
14 #define DUMUX_INFILTRATION_THREEP_PROBLEM_HH
15
16 #include <dumux/common/boundarytypes.hh>
17 #include <dumux/common/numeqvector.hh>
18
19 #include <dumux/porousmediumflow/problem.hh>
20
21 namespace Dumux {
22
23 /*!
24 * \ingroup ThreePTests
25 * \brief Isothermal NAPL infiltration problem: LNAPL contaminates
26 * the unsaturated and the saturated groundwater zone.
27 *
28 * The 2D domain of this test problem is 500m long and 10m deep, where
29 * the lower part represents a slightly inclined groundwater table, and the
30 * upper part is the vadose zone.
31 * A LNAPL (Non-Aqueous Phase Liquid which is lighter than water) infiltrates
32 * (modelled with a Neumann boundary condition) into the vadose zone. Upon
33 * reaching the water table, it spreads (since lighter than water) and migrates
34 * on top of the water table in the direction of the slope.
35 * On its way through the vadose zone, it leaves a trace of residually trapped
36 * immobile NAPL, which can in the following dissolve and evaporate slowly,
37 * and eventually be transported by advection and diffusion.
38 *
39 * Left and right boundaries are constant head boundaries (Dirichlet),
40 * Top and bottom are Neumann boundaries, all no-flow except for the small
41 * infiltration zone in the upper left part.
42 *
43 * This problem uses the \ref ThreePModel.
44 *
45 * This problem should typically be simulated for 30 days.
46 * A good choice for the initial time step size is 60s.
47 * */
48 template <class TypeTag >
49 class InfiltrationThreePProblem : public PorousMediumFlowProblem<TypeTag>
50 {
51 using ParentType = PorousMediumFlowProblem<TypeTag>;
52
53 using Scalar = GetPropType<TypeTag, Properties::Scalar>;
54 using GridView = typename GetPropType<TypeTag, Properties::GridGeometry>::GridView;
55 using Indices = typename GetPropType<TypeTag, Properties::ModelTraits>::Indices;
56
57 enum {
58 pressureIdx = Indices::pressureIdx,
59 swIdx = Indices::swIdx,
60 snIdx = Indices::snIdx,
61
62 // world dimension
63 dimWorld = GridView::dimensionworld
64 };
65
66 using PrimaryVariables = GetPropType<TypeTag, Properties::PrimaryVariables>;
67 using NumEqVector = Dumux::NumEqVector<PrimaryVariables>;
68 using BoundaryTypes = Dumux::BoundaryTypes<GetPropType<TypeTag, Properties::ModelTraits>::numEq()>;
69 using FluidSystem = GetPropType<TypeTag, Properties::FluidSystem>;
70 using GridGeometry = GetPropType<TypeTag, Properties::GridGeometry>;
71
72 using Element = typename GridView::template Codim<0>::Entity;
73 using GlobalPosition = typename Element::Geometry::GlobalCoordinate;
74
75 public:
76 2 InfiltrationThreePProblem(std::shared_ptr<const GridGeometry> gridGeometry)
77
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)
78 {
79
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 FluidSystem::init(282.15, 284.15, 3, 8e4, 3e5, 200);
80
81
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");
82
83
2/4
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
4 this->spatialParams().plotMaterialLaw();
84 2 time_ = 0.0;
85 2 }
86
87 /*!
88 * \name Problem parameters
89 */
90 // \{
91 void setTime(Scalar time)
92
1/2
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
16 { time_ = time; }
93
94 /*!
95 * \brief The problem name.
96 *
97 * This is used as a prefix for files generated by the simulation.
98 */
99 const std::string& name() const
100
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 { return name_; }
101
102 // \}
103
104 /*!
105 * \name Boundary conditions
106 */
107 // \{
108
109 /*!
110 * \brief Specifies which kind of boundary condition should be
111 * used for which equation on a given boundary segment.
112 *
113 * \param globalPos The position for which the bc type should be evaluated
114 */
115 13376 BoundaryTypes boundaryTypesAtPos(const GlobalPosition &globalPos) const
116 {
117 13376 BoundaryTypes values;
118
119
8/8
✓ Branch 0 taken 12256 times.
✓ Branch 1 taken 1120 times.
✓ Branch 2 taken 12256 times.
✓ Branch 3 taken 1120 times.
✓ Branch 4 taken 12256 times.
✓ Branch 5 taken 1120 times.
✓ Branch 6 taken 12256 times.
✓ Branch 7 taken 1120 times.
53504 if(globalPos[0] > this->gridGeometry().bBoxMax()[0] - eps_
120
12/12
✓ Branch 0 taken 12256 times.
✓ Branch 1 taken 1120 times.
✓ Branch 2 taken 11136 times.
✓ Branch 3 taken 1120 times.
✓ Branch 4 taken 11136 times.
✓ Branch 5 taken 1120 times.
✓ Branch 6 taken 11136 times.
✓ Branch 7 taken 1120 times.
✓ Branch 8 taken 11136 times.
✓ Branch 9 taken 1120 times.
✓ Branch 10 taken 11136 times.
✓ Branch 11 taken 1120 times.
13376 || globalPos[0] < this->gridGeometry().bBoxMin()[0] + eps_)
121 values.setAllDirichlet();
122 else
123 values.setAllNeumann();
124
125 13376 return values;
126 }
127
128 /*!
129 * \brief Evaluates the boundary conditions for a Dirichlet boundary segment.
130 *
131 * \param globalPos The position for which the bc type should be evaluated
132 *
133 * For this method, the \a values parameter stores primary variables.
134 */
135 PrimaryVariables dirichletAtPos(const GlobalPosition &globalPos) const
136 {
137 960 PrimaryVariables values(0.0);
138 960 initial_(values, globalPos);
139 return values;
140 }
141 /*!
142 * \brief Evaluates the boundary conditions for a Neumann boundary segment.
143 *
144 * \param globalPos The position of the integration point of the boundary segment.
145 *
146 * For this method, the \a values parameter stores the mass flux
147 * in normal direction of each phase. Negative values mean influx.
148 */
149 NumEqVector neumannAtPos(const GlobalPosition &globalPos) const
150 {
151 47168 NumEqVector values(0.0);
152
153 // negative values for injection
154
2/6
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 40768 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6400 times.
✗ Branch 5 not taken.
47168 if (time_ < 2592000.0 - eps_)
155 {
156
12/18
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 14144 times.
✓ Branch 7 taken 26624 times.
✓ Branch 8 taken 1664 times.
✓ Branch 9 taken 12480 times.
✓ Branch 10 taken 1664 times.
✓ Branch 11 taken 12480 times.
✓ Branch 12 taken 2304 times.
✓ Branch 13 taken 4096 times.
✓ Branch 14 taken 384 times.
✓ Branch 15 taken 1920 times.
✓ Branch 16 taken 384 times.
✓ Branch 17 taken 1920 times.
47168 if ((globalPos[0] < 175.0 + eps_) && (globalPos[0] > 155.0 - eps_)
157
24/36
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✓ Branch 12 taken 14144 times.
✓ Branch 13 taken 26624 times.
✓ Branch 14 taken 832 times.
✓ Branch 15 taken 832 times.
✓ Branch 16 taken 832 times.
✓ Branch 17 taken 832 times.
✓ Branch 18 taken 832 times.
✓ Branch 19 taken 832 times.
✓ Branch 20 taken 832 times.
✓ Branch 21 taken 832 times.
✓ Branch 22 taken 832 times.
✓ Branch 23 taken 832 times.
✓ Branch 24 taken 2304 times.
✓ Branch 25 taken 4096 times.
✓ Branch 26 taken 192 times.
✓ Branch 27 taken 192 times.
✓ Branch 28 taken 192 times.
✓ Branch 29 taken 192 times.
✓ Branch 30 taken 192 times.
✓ Branch 31 taken 192 times.
✓ Branch 32 taken 192 times.
✓ Branch 33 taken 192 times.
✓ Branch 34 taken 192 times.
✓ Branch 35 taken 192 times.
57408 && (globalPos[1] > this->gridGeometry().bBoxMax()[1] - eps_))
158 {
159 // mol fluxes, convert with M(Mesit.)=0,120 kg/mol --> 1.2e-4 kg/(sm)
160 2048 values[Indices::conti0EqIdx + FluidSystem::nCompIdx] = -0.001;
161 }
162 }
163
164 return values;
165 }
166
167 // \}
168
169 /*!
170 * \name Volume terms
171 */
172 // \{
173
174 /*!
175 * \brief Evaluates the initial value for a control volume.
176 *
177 * \param globalPos The position for which the initial condition should be evaluated
178 *
179 * For this method, the \a values parameter stores primary
180 * variables.
181 */
182 PrimaryVariables initialAtPos(const GlobalPosition &globalPos) const
183 {
184 1061 PrimaryVariables values(0.0);
185 1061 initial_(values, globalPos);
186 return values;
187 }
188
189 private:
190 // internal method for the initial condition (reused for the
191 // dirichlet conditions!)
192 2021 void initial_(PrimaryVariables &values,
193 const GlobalPosition &globalPos) const
194 {
195
2/2
✓ Branch 0 taken 1084 times.
✓ Branch 1 taken 937 times.
2021 const Scalar y = globalPos[1];
196
2/2
✓ Branch 0 taken 1084 times.
✓ Branch 1 taken 937 times.
2021 const Scalar x = globalPos[0];
197 2021 Scalar sw, swr=0.12, sgr=0.03;
198
199
2/2
✓ Branch 0 taken 1084 times.
✓ Branch 1 taken 937 times.
2021 if (y > (-1e-3*x + 5) - eps_)
200 {
201 1084 Scalar pc = 9.81 * 1000.0 * (y - (-5e-4*x + 5));
202
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 1068 times.
1084 if (pc < 0.0) pc = 0.0;
203
204 1084 sw = invertPcgw_(pc,
205 2168 this->spatialParams().fluidMatrixInteractionAtPos(globalPos));
206
2/2
✓ Branch 0 taken 756 times.
✓ Branch 1 taken 328 times.
1084 if (sw < swr) sw = swr;
207
2/2
✓ Branch 0 taken 68 times.
✓ Branch 1 taken 1016 times.
1084 if (sw > 1.-sgr) sw = 1.-sgr;
208
209 1084 values[pressureIdx] = 1e5 ;
210 1084 values[swIdx] = sw;
211 2168 values[snIdx] = 0.;
212 }
213 else
214 {
215 937 values[pressureIdx] = 1e5 + 9.81 * 1000.0 * ((-5e-4*x + 5) - y);
216 937 values[swIdx] = 1.-sgr;
217 1874 values[snIdx] = 0.;
218 }
219 2021 }
220
221 // small solver inverting the pc curve
222 template<class FMInteraction>
223 1084 static Scalar invertPcgw_(Scalar pcIn, const FMInteraction& fluidMatrixInteraction)
224 {
225 Scalar lower,upper;
226 int k;
227 1084 int maxIt = 50;
228 1084 Scalar bisLimit = 1.;
229 Scalar sw, pcgw;
230 1084 lower=0.0; upper=1.0;
231
1/2
✓ Branch 0 taken 17345 times.
✗ Branch 1 not taken.
17345 for (k=1; k<=25; k++)
232 {
233 17345 sw = 0.5*(upper+lower);
234 17345 pcgw = fluidMatrixInteraction.pcgw(sw, 0.0);
235 17345 Scalar delta = pcgw-pcIn;
236
2/2
✓ Branch 0 taken 9553 times.
✓ Branch 1 taken 7792 times.
17345 if (delta<0.) delta*=-1.;
237
2/2
✓ Branch 0 taken 1084 times.
✓ Branch 1 taken 16261 times.
17345 if (delta<bisLimit)
238 {
239 1084 return(sw);
240 }
241 if (k==maxIt) {
242 return(sw);
243 }
244
2/2
✓ Branch 0 taken 9026 times.
✓ Branch 1 taken 7235 times.
16261 if (pcgw>pcIn) lower=sw;
245 9026 else upper=sw;
246 }
247 return(sw);
248 }
249
250 static constexpr Scalar eps_ = 1e-6;
251 std::string name_;
252 Scalar time_;
253 };
254
255 } // end namespace Dumux
256
257 #endif
258