GCC Code Coverage Report


Directory: ../../../builds/dumux-repositories/
File: /builds/dumux-repositories/dumux/examples/biomineralization/problem.hh
Date: 2024-09-21 20:52:54
Exec Total Coverage
Lines: 196 202 97.0%
Functions: 7 10 70.0%
Branches: 123 246 50.0%

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 #ifndef DUMUX_MICP_COLUMN_SIMPLE_CHEM_PROBLEM_HH
8 #define DUMUX_MICP_COLUMN_SIMPLE_CHEM_PROBLEM_HH
9
10 // ## Initial and boundary conditions (`problem.hh`)
11 //
12 // This file contains the __problem class__ which defines the initial and boundary
13 // conditions for the biominearalization example.
14 //
15 // [[content]]
16 //
17 // ### Include files
18 // [[codeblock]]
19 // This header contains the PorousMediumFlowProblem class
20 #include <dumux/porousmediumflow/problem.hh>
21 #include <dumux/common/boundarytypes.hh> // for `BoundaryTypes`
22 #include <dumux/common/properties.hh> // GetPropType
23 #include <dumux/common/numeqvector.hh> // for `NumEqVector`
24 #include <dumux/material/components/ammonia.hh>
25 #include <dumux/discretization/evalgradients.hh>
26 #include <dumux/io/container.hh>
27 #include <algorithm> // for std::transform
28 // [[/codeblock]]
29
30 // ### The problem class
31 // The problem class defines the boundary and initial conditions.
32 // As this is a biomineralization problem in porous media, we inherit from the porous-media-flow problem
33
34 // [[codeblock]]
35 namespace Dumux {
36
37 template <class TypeTag>
38 class MICPColumnProblemSimpleChemistry : public PorousMediumFlowProblem<TypeTag>
39 {
40 using ParentType = PorousMediumFlowProblem<TypeTag>;
41 using Scalar = GetPropType<TypeTag, Properties::Scalar>;
42 using NH3 = Components::Ammonia<Scalar>; // for molar mass of Ammonia
43 using FluidSystem = GetPropType<TypeTag, Properties::FluidSystem>;
44 using SolidSystem = GetPropType<TypeTag, Properties::SolidSystem>;
45 using VolumeVariables = GetPropType<TypeTag, Properties::VolumeVariables>;
46 using FluxVariables = GetPropType<TypeTag, Properties::FluxVariables>;
47 using Indices = typename GetPropType<TypeTag, Properties::ModelTraits>::Indices;
48
49 // We define some indices for convenience to be used later when defining the initial and boundary conditions
50 enum {
51 numComponents = FluidSystem::numComponents,
52
53 pressureIdx = Indices::pressureIdx,
54 switchIdx = Indices::switchIdx, //Saturation
55 xwNaIdx = FluidSystem::NaIdx,
56 xwClIdx = FluidSystem::ClIdx,
57 xwCaIdx = FluidSystem::CaIdx,
58 xwUreaIdx = FluidSystem::UreaIdx,
59 xwO2Idx = FluidSystem::O2Idx,
60 xwBiosubIdx = FluidSystem::GlucoseIdx,
61 xwSuspendedBiomassIdx = FluidSystem::SuspendedBiomassIdx,
62 phiBiofilmIdx = numComponents,
63 phiCalciteIdx = numComponents + 1,
64
65 //Indices of the components
66 wCompIdx = FluidSystem::wCompIdx,
67 nCompIdx = FluidSystem::nCompIdx,
68 NaIdx = FluidSystem::NaIdx,
69 ClIdx = FluidSystem::ClIdx,
70 CaIdx = FluidSystem::CaIdx,
71 UreaIdx = FluidSystem::UreaIdx,
72 O2Idx = FluidSystem::O2Idx,
73 BiosubIdx = FluidSystem::GlucoseIdx,
74 SuspendedBiomassIdx = FluidSystem::SuspendedBiomassIdx,
75
76 wPhaseIdx = FluidSystem::wPhaseIdx,
77 conti0EqIdx = Indices::conti0EqIdx,
78
79 // Phase State
80 wPhaseOnly = Indices::firstPhaseOnly,
81 bothPhases = Indices::bothPhases
82 };
83
84 using PrimaryVariables = GetPropType<TypeTag, Properties::PrimaryVariables>;
85 using NumEqVector = Dumux::NumEqVector<PrimaryVariables>;
86 using BoundaryTypes = Dumux::BoundaryTypes<PrimaryVariables::size()>;
87 using ElementVolumeVariables = typename GetPropType<TypeTag, Properties::GridVolumeVariables>::LocalView;
88 using GridGeometry = GetPropType<TypeTag, Properties::GridGeometry>;
89 using GridView = typename GridGeometry::GridView;
90 using Element = typename GridView::template Codim<0>::Entity;
91 using FVElementGeometry = typename GridGeometry::LocalView;
92 using SubControlVolume = typename GridGeometry::SubControlVolume;
93 using GlobalPosition = typename Element::Geometry::GlobalCoordinate;
94 static constexpr int dim = GridView::dimension;
95 // [[/codeblock]]
96 //
97 // We define an enum class to distinguish between different injection processes.
98 // We will use these later in the definition of the Neumann boundary conditions.
99 enum class InjectionProcess : int
100 {
101 noInjection = -99,
102 noFlow = -9,
103 rinse = -1,
104 resuscitation = 3,
105 inoculation = 2,
106 mineralization = 1
107 };
108 //
109 // ### Reading of parameters specified in the params.input file
110 // [[details]] parameters
111 // [[codeblock]]
112 public:
113 // This is the constructor of our problem class.
114 1 MICPColumnProblemSimpleChemistry(std::shared_ptr<const GridGeometry> gridGeometry)
115
9/28
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✓ Branch 13 taken 1 times.
✓ Branch 15 taken 1 times.
✗ Branch 16 not taken.
✓ Branch 18 taken 1 times.
✗ Branch 19 not taken.
✓ Branch 21 taken 1 times.
✗ Branch 22 not taken.
✓ Branch 24 taken 1 times.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
✗ Branch 27 not taken.
✗ Branch 28 not taken.
✗ Branch 29 not taken.
✗ Branch 32 not taken.
✗ Branch 33 not taken.
✗ Branch 34 not taken.
✗ Branch 35 not taken.
✗ Branch 36 not taken.
✗ Branch 37 not taken.
3 : ParentType(gridGeometry)
116 {
117 // We read the parameters from the params.input file.
118
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
1 name_ = getParam<std::string>("Problem.Name");
119
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 temperature_ = getParam<Scalar>("Problem.Temperature");
120
121 // biomass parameters
122
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 ca1_ = getParam<Scalar>("BioCoefficients.Ca1");
123
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 ca2_ = getParam<Scalar>("BioCoefficients.Ca2");
124
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 cd1_ = getParam<Scalar>("BioCoefficients.Cd1");
125
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 dc0_ = getParam<Scalar>("BioCoefficients.Dc0");
126
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 kmue_ = getParam<Scalar>("BioCoefficients.Kmue");
127
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 f_ = getParam<Scalar>("BioCoefficients.F");
128
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 ke_ = getParam<Scalar>("BioCoefficients.Ke");
129
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 ks_ = getParam<Scalar>("BioCoefficients.Ks");
130
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 yield_ = getParam<Scalar>("BioCoefficients.Yield");
131
132 // ureolysis kinetic parameters
133
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 kub_ = getParam<Scalar>("UreolysisCoefficients.Kub");
134
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 kurease_ = getParam<Scalar>("UreolysisCoefficients.Kurease");
135
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 ku_ = getParam<Scalar>("UreolysisCoefficients.Ku");
136
137 // initial values
138
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 densityW_ = getParam<Scalar>("Initial.DensityW");
139
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 initPressure_ = getParam<Scalar>("Initial.Pressure");
140
141
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 initxwTC_ = getParam<Scalar>("Initial.XwTC");
142
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 initxwNa_ = getParam<Scalar>("Initial.XwNa");
143
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 initxwCl_ = getParam<Scalar>("Initial.XwCl");
144
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 initxwCa_ = getParam<Scalar>("Initial.XwCa");
145
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 initxwUrea_ = getParam<Scalar>("Initial.XwUrea");
146
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 initxwTNH_ = getParam<Scalar>("Initial.XwTNH");
147
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 initxwO2_ = getParam<Scalar>("Initial.XwO2");
148
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 initxwBiosub_ = getParam<Scalar>("Initial.XwSubstrate");
149
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 initxwBiosusp_ = getParam<Scalar>("Initial.XwSuspendedBiomass");
150
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 initCalcite_ = getParam<Scalar>("Initial.Calcite");
151
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 initBiofilm_ = getParam<Scalar>("Initial.Biofilm");
152
153
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 xwNaCorr_ = getParam<Scalar>("Initial.XwNaCorr");
154
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 xwClCorr_ = getParam<Scalar>("Initial.XwClCorr");
155
156 // injection values
157
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 injQ_ = getParam<Scalar>("Injection.FlowRate");
158
159
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 injTC_ = getParam<Scalar>("Injection.MassFracTC");
160
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 injNa_ = getParam<Scalar>("Injection.ConcentrationNa");
161
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 injCa_ = getParam<Scalar>("Injection.ConcentrationCa");
162
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 injUrea_ = getParam<Scalar>("Injection.ConcentrationUrea");
163
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 injTNH_ = getParam<Scalar>("Injection.ConcentrationTNH");
164
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 injO2_ = getParam<Scalar>("Injection.ConcentrationO2");
165
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 injSub_ = getParam<Scalar>("Injection.ConcentrationSubstrate");
166
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 injBiosusp_= getParam<Scalar>("Injection.ConcentrationSuspendedBiomass");
167
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 injNaCorr_ = getParam<Scalar>("Injection.ConcentrationNaCorr");
168 // [[/codeblock]]
169 // [[/details]]
170 //
171 // ### Reading of the temporal sequence of the different types of injection
172 // Here, the number of injections and the corresponding parameters are defined based on what is specified in the input files.
173 // [[codeblock]]
174 // We get the number of injections and the injection data file name from params.input
175
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 numInjections_ = getParam<int>("Injection.NumInjections");
176
177 // We resize the permeability vector containing the permeabilities for the additional output
178
3/6
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
3 permeability_.resize(gridGeometry->numDofs());
179
180 // We read from the injection data file which injection type we have in each episode.
181 // We will use this in the Neumann boundary condition to set time dependent, changing boundary conditions.
182 // We do this similarly to the episode ends in the main file.
183
3/8
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
3 const auto injType = readFileToContainer<std::vector<int>>("injection_type.dat");
184 // translate integer to InjectionProcess type
185 4 std::transform(injType.begin(), injType.end(), std::back_inserter(injectionType_),
186 [](int n){ return static_cast<InjectionProcess>(n); });
187
188
189 // [[/codeblock]]
190
191 // We check the injection data against the number of injections specified in the parameter file
192 // and print an error message if the test fails
193 // [[codeblock]]
194
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
2 if (injectionType_.size() != numInjections_)
195 DUNE_THROW(Dune::IOError, "numInjections from the parameterfile and the number of injection types "
196 << "specified in the injection data file do not match!\n"
197 << "numInjections from parameter file: " << numInjections_ << "\n"
198 << "numInjTypes from injection data file: "<< injectionType_.size());
199
200 // Initialize the fluidsystem
201
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
2 FluidSystem::init(/*startTemp=*/temperature_ -5.0, /*endTemp=*/temperature_ +5.0, /*tempSteps=*/5,
202 /*startPressure=*/1e4, /*endPressure=*/1e6, /*pressureSteps=*/500);
203 1 }
204 // [[/codeblock]]
205
206 // In the following, functions to set the time, time step size and the index of the episode
207 // are declared which are used the time loop in main.cc
208 // [[codeblock]]
209 void setTime(const Scalar t)
210
1/2
✓ Branch 1 taken 275 times.
✗ Branch 2 not taken.
275 { time_ = t; }
211
212 // We need the time step size to regularize the reactive source terms.
213 void setTimeStepSize(const Scalar dt)
214
1/2
✓ Branch 1 taken 275 times.
✗ Branch 2 not taken.
275 { timeStepSize_ = dt; }
215
216 // We need the episode index to choose the right Neumann boundary condition for each episode based on the injection data.
217 void setEpisodeIdx(const Scalar epIdx)
218
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
8 { episodeIdx_ = epIdx; }
219 // [[/codeblock]]
220
221 // Here, functions to return the injectionType and the name of the problem are defined
222 // [[codeblock]]
223 int injectionType(int episodeIdx) const
224 { return injectionType_[episodeIdx]; }
225
226 // Get the problem name. It is used as a prefix for files generated by the simulation.
227 const std::string& name() const
228
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 { return name_; }
229 // [[/codeblock]]
230
231 // #### Boundary conditions
232 // With the following function we define the type of boundary conditions depending on the location. Two types of boundary conditions
233 // can be specified: Dirichlet or Neumann boundary condition. On a Dirichlet boundary, the values of the
234 // primary variables need to be fixed. On a Neumann boundary condition, values for derivatives need to be fixed.
235
236 // [[codeblock]]
237 6950 BoundaryTypes boundaryTypesAtPos(const GlobalPosition &globalPos) const
238 {
239 6950 BoundaryTypes bcTypes;
240 // We set all to Neumann, except for the top boundary, which is set to Dirichlet.
241 13900 const Scalar zmax = this->gridGeometry().bBoxMax()[dim - 1];
242 6950 bcTypes.setAllNeumann();
243
2/2
✓ Branch 0 taken 3475 times.
✓ Branch 1 taken 3475 times.
6950 if (globalPos[dim - 1] > zmax - eps_)
244 bcTypes.setAllDirichlet();
245
246 6950 return bcTypes;
247 }
248 // [[/codeblock]]
249
250 // We define the Dirichlet boundary conditions
251 // [[codeblock]]
252 1899 PrimaryVariables dirichletAtPos(const GlobalPosition &globalPos) const
253 {
254 1899 PrimaryVariables priVars(0.0);
255 1899 priVars.setState(wPhaseOnly);
256 // We recycle the initial conditions, but additionally enforce that substrate and oxygen necessary for biomass growth are zero.
257 1899 priVars = initial_(globalPos);
258 3798 priVars[xwBiosubIdx] = 0.0;
259 3798 priVars[xwO2Idx] = 0.0;
260 1899 return priVars;
261 }
262 // [[/codeblock]]
263
264 // The injections can be described with a Neumann boundary condition.
265 // Since we have multiple injections durng the whole simulation period, the Neumann boundary conditions in this case are time or rather episode depended.
266 // [[codeblock]]
267 36248 NumEqVector neumannAtPos(const GlobalPosition& globalPos) const
268 {
269 // We only have injection at the bottom, negative values for injection
270
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 36248 times.
36248 if (globalPos[dim - 1] > eps_)
271 return NumEqVector(0.0);
272
273 // We calculate the injected water velocity based on the volume flux injected into a 1 inch diameter column.
274 36248 const Scalar diameter = 0.0254;
275 36248 const Scalar waterFlux = injQ_/(3.14*diameter*diameter/4.); //[m/s]
276
2/2
✓ Branch 0 taken 26128 times.
✓ Branch 1 taken 10120 times.
36248 const auto injProcess = injectionType_[episodeIdx_];
277
278 // We also have no-injection, no-flow periods, which are coded for by -99 or 9.
279 // Thus, for no flow, we set the Neumann BC to zero for all components.
280
2/2
✓ Branch 0 taken 26128 times.
✓ Branch 1 taken 10120 times.
36248 if (injProcess == InjectionProcess::noInjection || injProcess == InjectionProcess::noFlow)
281 26128 return NumEqVector(0.0);
282
283 // We set the injection BC to the basic rinse injection and later only change the BC for those components that are different.
284 10120 NumEqVector values(0.0);
285
286 10120 values[conti0EqIdx + wCompIdx] = -waterFlux * 996/FluidSystem::molarMass(wCompIdx);
287 10120 values[conti0EqIdx + nCompIdx] = -waterFlux * injTC_*996 /FluidSystem::molarMass(nCompIdx);
288 10120 values[conti0EqIdx + xwCaIdx] = 0;
289 10120 values[conti0EqIdx + xwSuspendedBiomassIdx] = 0;
290 10120 values[conti0EqIdx + xwBiosubIdx] = -waterFlux * injSub_ /FluidSystem::molarMass(xwBiosubIdx);
291 10120 values[conti0EqIdx + xwO2Idx] = -waterFlux * injO2_ /FluidSystem::molarMass(O2Idx);
292 10120 values[conti0EqIdx + xwUreaIdx] = 0;
293 10120 values[conti0EqIdx + phiCalciteIdx] = 0;
294 10120 values[conti0EqIdx + phiBiofilmIdx] = 0;
295 10120 values[conti0EqIdx + xwNaIdx] = -waterFlux * (injNa_ + injNaCorr_) /FluidSystem::molarMass(NaIdx);
296 30360 values[conti0EqIdx + xwClIdx] = -waterFlux *injTNH_ /NH3::molarMass() //NH4Cl ---> mol Cl = mol NH4
297
2/2
✓ Branch 1 taken 368 times.
✓ Branch 2 taken 9752 times.
10120 -waterFlux *injNa_ /FluidSystem::molarMass(NaIdx); //NaCl ---> mol Cl = mol Na
298 // rinse, used as standard injection fluid
299
2/2
✓ Branch 0 taken 368 times.
✓ Branch 1 taken 9752 times.
10120 if (injProcess == InjectionProcess::rinse)
300 {
301 368 return values; // do not change anything.
302 }
303
304 // injProcess == 1 codes for an injection of mineralization medium containing urea and calcium chloride.
305 // Thus, we add BC terms for those components.
306 // Additionally, we need to adjust the amount of water injected due to the high concentration of other components injected.
307 // Finally, we need to adapt the injected NaCorr concentration to account for the lower pH.
308
2/2
✓ Branch 0 taken 345 times.
✓ Branch 1 taken 9407 times.
9752 else if (injProcess == InjectionProcess::mineralization)
309 {
310 345 values[conti0EqIdx + wCompIdx] = - waterFlux * 0.8716 * densityW_ /FluidSystem::molarMass(wCompIdx); //0.8716 factor accounts for less water per volume due to relatively high solute concentrations!
311 345 values[conti0EqIdx + nCompIdx] = - waterFlux * injTC_ * densityW_ /FluidSystem::molarMass(nCompIdx);
312 345 values[conti0EqIdx + xwCaIdx] = - waterFlux * injCa_/FluidSystem::molarMass(CaIdx);
313 345 values[conti0EqIdx + xwUreaIdx] = - waterFlux * injUrea_ /FluidSystem::molarMass(UreaIdx);
314 345 values[conti0EqIdx + xwNaIdx] = - waterFlux * injNa_ /FluidSystem::molarMass(NaIdx)
315 345 - waterFlux * injNaCorr_ /FluidSystem::molarMass(NaIdx)* 0.032;
316 1035 values[conti0EqIdx + xwClIdx] = - waterFlux * injTNH_ /NH3::molarMass() //NH4Cl ---> mol Cl = mol NH4
317 345 - waterFlux * 2 * injCa_/FluidSystem::molarMass(CaIdx) //+CaCl2 ---> mol Cl = mol Ca*2
318 345 -waterFlux *injNa_ /FluidSystem::molarMass(NaIdx); //NaCl ---> mol Cl = mol Na
319 345 return values;
320 }
321
322 // injProcess == 3 codes for a resuscitation injection to regrow biomass.
323 // It is similar to a rinse injection, but with added urea, which is what we add to the basic rinse
324
2/2
✓ Branch 0 taken 8740 times.
✓ Branch 1 taken 667 times.
9407 else if (injProcess == InjectionProcess::resuscitation )
325 {
326 8740 values[conti0EqIdx + xwUreaIdx] = - waterFlux * injUrea_ /FluidSystem::molarMass(UreaIdx);
327 8740 return values;
328 }
329
330 // injProcess == 2 codes for a inoculation or biomass injection.
331 // It is similar to a rinse injection, but with added suspended biomass, which is what we add to the basic rinse
332
1/2
✓ Branch 0 taken 667 times.
✗ Branch 1 not taken.
667 else if (injProcess == InjectionProcess::inoculation)
333 {
334 667 values[conti0EqIdx + xwSuspendedBiomassIdx] = -waterFlux * injBiosusp_ /FluidSystem::molarMass(xwSuspendedBiomassIdx);
335 667 return values;
336 }
337 else
338 DUNE_THROW(Dune::InvalidStateException, "Invalid injection process " << static_cast<int>(injProcess));
339 }
340 // [[/codeblock]]
341
342 // #### Initial conditions
343 // We specify the initial conditions for the primary variable depending
344 // on the location. Here, we set zero model fractions everywhere in the domain except for a strip
345 // at the bottom of the domain where we set an initial mole fraction of $`1e-9`$.
346 // [[codeblock]]
347 PrimaryVariables initialAtPos(const GlobalPosition& globalPos) const
348 57 { return initial_(globalPos); }
349
350 // [[/codeblock]]
351
352 // #### Reactive source and sink terms
353 // We calculate the reactive source and sink terms.
354 // For the details, see the "simplified chemistry case" in the dissertation of Hommel available at https://elib.uni-stuttgart.de/handle/11682/8787
355 // [[codeblock]]
356 4059776 NumEqVector source(const Element &element,
357 const FVElementGeometry& fvGeometry,
358 const ElementVolumeVariables& elemVolVars,
359 const SubControlVolume &scv) const
360 {
361 4059776 const auto elemSol = elementSolution(element, elemVolVars, fvGeometry);
362 12179328 const auto gradPw = evalGradients(element,
363 element.geometry(),
364 this->gridGeometry(),
365 elemSol,
366 4059776 scv.center())[pressureIdx];
367 4059776 const Scalar scvPotGradNorm = gradPw.two_norm();
368
369 //define and compute some parameters for siplicity:
370 8119552 const Scalar porosity = elemVolVars[scv].porosity();
371 4059776 Scalar initialPorosity = 1.0;
372 4059776 constexpr int numActiveComps = SolidSystem::numComponents-SolidSystem::numInertComponents;
373
2/2
✓ Branch 0 taken 4059776 times.
✓ Branch 1 taken 4059776 times.
8119552 for (int i = numActiveComps; i<SolidSystem::numComponents; ++i)
374 12179328 initialPorosity -= elemVolVars[scv].solidVolumeFraction(i);
375
376 8119552 const Scalar Sw = elemVolVars[scv].saturation(wPhaseIdx);
377 4059776 const Scalar xlSalinity = elemVolVars[scv].moleFraction(wPhaseIdx,NaIdx)
378 12179328 + elemVolVars[scv].moleFraction(wPhaseIdx,CaIdx)
379 8119552 + elemVolVars[scv].moleFraction(wPhaseIdx,ClIdx);
380 8119552 const Scalar densityBiofilm = elemVolVars[scv].solidComponentDensity(SolidSystem::BiofilmIdx);
381 8119552 const Scalar densityCalcite = elemVolVars[scv].solidComponentDensity(SolidSystem::CalciteIdx);
382 4059776 const Scalar cBio = std::max(0.0, elemVolVars[scv].moleFraction(wPhaseIdx, SuspendedBiomassIdx)
383 12179328 * elemVolVars[scv].molarDensity(wPhaseIdx)
384
2/2
✓ Branch 1 taken 4022639 times.
✓ Branch 2 taken 37137 times.
4059776 * FluidSystem::molarMass(SuspendedBiomassIdx)); //[kg_suspended_Biomass/m³_waterphase]
385
6/6
✓ Branch 0 taken 293728 times.
✓ Branch 1 taken 3766048 times.
✓ Branch 2 taken 293728 times.
✓ Branch 3 taken 3766048 times.
✓ Branch 4 taken 293728 times.
✓ Branch 5 taken 3766048 times.
12179328 const Scalar volFracCalcite = std::max(0.0, elemVolVars[scv].solidVolumeFraction(SolidSystem::CalciteIdx));
386
6/6
✓ Branch 0 taken 4022662 times.
✓ Branch 1 taken 37114 times.
✓ Branch 2 taken 4022662 times.
✓ Branch 3 taken 37114 times.
✓ Branch 4 taken 4022662 times.
✓ Branch 5 taken 37114 times.
12179328 const Scalar volFracBiofilm = std::max(0.0, elemVolVars[scv].solidVolumeFraction(SolidSystem::BiofilmIdx));
387 4059776 const Scalar massBiofilm = densityBiofilm * volFracBiofilm;
388 4059776 const Scalar cSubstrate = std::max(0.0, elemVolVars[scv].moleFraction(wPhaseIdx, BiosubIdx)
389 12179328 * elemVolVars[scv].molarDensity(wPhaseIdx)
390
2/2
✓ Branch 1 taken 4025170 times.
✓ Branch 2 taken 34606 times.
4059776 * FluidSystem::molarMass(BiosubIdx)); //[kg_substrate/m³_waterphase]
391 4059776 const Scalar cO2 = std::max(0.0, elemVolVars[scv].moleFraction(wPhaseIdx, O2Idx)
392 12179328 * elemVolVars[scv].molarDensity(wPhaseIdx)
393
2/2
✓ Branch 1 taken 3936839 times.
✓ Branch 2 taken 122937 times.
4059776 * FluidSystem::molarMass(O2Idx)); //[kg_oxygen/m³_waterphase]
394 8119552 const Scalar mUrea = std::max(0.0, moleFracToMolality(elemVolVars[scv].moleFraction(wPhaseIdx,UreaIdx),
395 xlSalinity,
396 8119552 elemVolVars[scv].moleFraction(wPhaseIdx,nCompIdx))); //[mol_urea/kg_H2O]
397 // compute rate of ureolysis:
398 4059776 const Scalar vmax = kurease_;
399 4059776 const Scalar Zub = kub_ * massBiofilm; // [kgurease/m³]
400 4059776 const Scalar rurea = vmax * Zub * mUrea / (ku_ + mUrea); //[mol/m³s]
401
402 // compute precipitation rate of calcite, no dissolution! Simplification: rprec = rurea
403 // additionally regularize the precipitation rate that we do not precipitate more calcium than available.
404
4/4
✓ Branch 0 taken 1126645 times.
✓ Branch 1 taken 2933131 times.
✓ Branch 2 taken 1126645 times.
✓ Branch 3 taken 2933131 times.
8119552 const Scalar maxPrecipitationRate = elemVolVars[scv].moleFraction(wPhaseIdx,CaIdx) * Sw * porosity
405
4/4
✓ Branch 0 taken 1126645 times.
✓ Branch 1 taken 2933131 times.
✓ Branch 2 taken 1126645 times.
✓ Branch 3 taken 2933131 times.
8119552 * elemVolVars[scv].molarDensity(wPhaseIdx) / timeStepSize_;
406
2/2
✓ Branch 0 taken 1126645 times.
✓ Branch 1 taken 2933131 times.
4059776 const Scalar rprec = std::min(rurea, maxPrecipitationRate);
407
408 //compute biomass growth coefficient and rate
409 4059776 const Scalar mue = kmue_ * cSubstrate / (ks_ + cSubstrate) * cO2 / (ke_ + cO2);// [1/s]
410 4059776 const Scalar rgf = mue * massBiofilm; //[kg/m³s]
411 4059776 const Scalar rgb = mue * porosity * Sw * cBio; //[kg/m³s]
412
413 // compute biomass decay coefficient and rate:
414 4059776 const Scalar dcf = dc0_ + (rprec * SolidSystem::molarMass(SolidSystem::CalciteIdx)
415 4059776 /(densityCalcite * (initialPorosity - volFracCalcite)));
416 4059776 const Scalar dcb = dc0_; //[1/s]
417 4059776 const Scalar rdcf = dcf * massBiofilm; //[kg/m³s]
418 4059776 const Scalar rdcb = dcb * porosity * Sw * cBio; //[kg/m³s]
419
420 // compute attachment coefficient and rate:
421 4059776 const Scalar ka = ca1_ * volFracBiofilm + ca2_; //[1/s]
422 4059776 const Scalar ra = ka * porosity * Sw * cBio; //[kg/m³s]
423
424 // compute detachment coefficient and rate:
425 4059776 const Scalar cd2 = volFracBiofilm / (initialPorosity - volFracCalcite); //[-]
426 4059776 const Scalar kd = cd1_ * std::pow((porosity * Sw * scvPotGradNorm),0.58) + cd2 * mue; //[1/s]
427 4059776 const Scalar rd = kd * massBiofilm; //[kg/m³s]
428
429 // rprec[mol/m³s]
430 // rurea[mol/m³s]
431 // rgb + rdcb + ra + rd [kg/m³s]
432 // source[kg/m³s]
433 4059776 NumEqVector source(0.0);
434 4059776 source[wCompIdx] += 0;
435 4059776 source[nCompIdx] += rurea - rprec;
436 4059776 source[NaIdx] += 0;
437 4059776 source[ClIdx] += 0;
438 4059776 source[CaIdx] += - rprec;
439 4059776 source[UreaIdx] += - rurea;
440 4059776 source[O2Idx] += -(rgf + rgb) *f_/yield_ / FluidSystem::molarMass(O2Idx);
441 4059776 source[BiosubIdx] += -(rgf + rgb) / yield_ / FluidSystem::molarMass(BiosubIdx);
442 4059776 source[SuspendedBiomassIdx] += (rgb - rdcb - ra + rd) / FluidSystem::molarMass(SuspendedBiomassIdx);
443 4059776 source[phiBiofilmIdx] += (rgf - rdcf + ra - rd) / SolidSystem::molarMass(SolidSystem::BiofilmIdx);
444 8119552 source[phiCalciteIdx] += + rprec;
445
446 4059776 return source;
447 }
448 // [[/codeblock]]
449
450 // The permeability is added to the vtk output
451 // [[codeblock]]
452 // Function to return the permeability for additional vtk output
453 const std::vector<Scalar>& getPermeability()
454
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 { return permeability_; }
455
456 // Function to update the permeability for additional vtk output
457 template<class SolutionVector>
458 294 void updateVtkOutput(const SolutionVector& curSol)
459 {
460
1/2
✓ Branch 3 taken 16758 times.
✗ Branch 4 not taken.
33810 for (const auto& element : elements(this->gridGeometry().gridView()))
461 {
462 32928 const auto elemSol = elementSolution(element, curSol, this->gridGeometry());
463
2/4
✓ Branch 1 taken 16464 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 16464 times.
✗ Branch 5 not taken.
49392 auto fvGeometry = localView(this->gridGeometry());
464
1/2
✓ Branch 1 taken 16464 times.
✗ Branch 2 not taken.
16464 fvGeometry.bindElement(element);
465
4/4
✓ Branch 0 taken 32928 times.
✓ Branch 1 taken 16464 times.
✓ Branch 2 taken 32928 times.
✓ Branch 3 taken 16464 times.
98784 for (const auto& scv : scvs(fvGeometry))
466 {
467 32928 VolumeVariables volVars;
468
1/2
✓ Branch 1 taken 32928 times.
✗ Branch 2 not taken.
32928 volVars.update(elemSol, *this, element, scv);
469 32928 const auto dofIdxGlobal = scv.dofIndex();
470 65856 permeability_[dofIdxGlobal] = volVars.permeability();
471 }
472 }
473 294 }
474 // [[/codeblock]]
475
476 // ### Declaring all necessary variables and private functions
477 // The internal methods are defined here
478 // [[codeblock]]
479 private:
480 // Internal method for the initial condition reused for the dirichlet conditions.
481 1956 PrimaryVariables initial_(const GlobalPosition &globalPos) const
482 {
483 1956 PrimaryVariables priVars(0.0);
484 3912 priVars.setState(wPhaseOnly);
485 3912 priVars[pressureIdx] = initPressure_ ; //70e5; // - (maxHeight - globalPos[1])*densityW_*9.81; //p_atm + rho*g*h
486 3912 priVars[switchIdx] = initxwTC_;
487 3912 priVars[xwNaIdx] = initxwNa_ + xwNaCorr_;
488 3912 priVars[xwClIdx] = initxwCl_ + initxwTNH_ + 2*initxwCa_ + xwClCorr_;
489 3912 priVars[xwCaIdx] = initxwCa_;
490 3912 priVars[xwUreaIdx] = initxwUrea_;
491 3912 priVars[xwO2Idx] = initxwO2_;
492 3912 priVars[xwBiosubIdx] = initxwBiosub_;
493 3912 priVars[xwSuspendedBiomassIdx] = initxwBiosusp_;
494 3912 priVars[phiBiofilmIdx] = initBiofilm_; // [m^3/m^3]
495 3912 priVars[phiCalciteIdx] = initCalcite_; // [m^3/m^3]
496 1956 return priVars;
497 }
498
499 // Internal method to calculate the molality of a component based on its mole fraction.
500 static Scalar moleFracToMolality(Scalar moleFracX, Scalar moleFracSalinity, Scalar moleFracCTot)
501 {
502
2/2
✓ Branch 0 taken 1250992 times.
✓ Branch 1 taken 2808784 times.
4059776 const Scalar molalityX = moleFracX / (1 - moleFracSalinity - moleFracCTot)
503 4059776 / FluidSystem::molarMass(FluidSystem::H2OIdx);
504 return molalityX;
505 }
506 // [[/codeblock]]
507
508 // The remainder of the class contains an epsilon value used for floating point comparisons
509 // and parameters needed to describe the chemical processes.
510 // Additionally the problem name, the peremability vector as well as some time-parameters are declared
511 // [[details]] private members
512 // eps is used as a small value for the definition of the boundary conditions
513 static constexpr Scalar eps_ = 1e-6;
514
515 // initial condition parameters
516 Scalar initPressure_;
517 Scalar densityW_;//1087; // rhow=1087;
518 Scalar initxwTC_;//2.3864e-7; // [mol/mol]
519 Scalar initxwNa_;//0;
520 Scalar initxwCl_;//0;
521 Scalar initxwCa_;//0;
522 Scalar initxwUrea_;//0;
523 Scalar initxwTNH_;//3.341641e-3;
524 Scalar initxwO2_;//4.4686e-6;
525 Scalar initxwBiosub_;//2.97638e-4;
526 Scalar initxwBiosusp_;//0;
527 Scalar xwNaCorr_;//2.9466e-6;
528 Scalar xwClCorr_;//0;
529 Scalar initBiofilm_;
530 Scalar initCalcite_;
531 Scalar temperature_;
532
533 // biomass parameters for source/sink calculations
534 Scalar ca1_;
535 Scalar ca2_;
536 Scalar cd1_;
537 Scalar dc0_;
538 Scalar kmue_ ;
539 Scalar f_;
540 Scalar ke_;
541 Scalar ks_;
542 Scalar yield_;
543 // urease parameters for source/sink calculations
544 Scalar kub_;
545 Scalar kurease_;
546 Scalar ku_;
547
548 // injection parameters
549 Scalar injQ_;
550 Scalar injTC_; // [kg/kg]
551 Scalar injNa_; // [kg/m³]
552 Scalar injCa_; // [kg/m³] //computed from CaCl2
553 Scalar injUrea_; // [kg/m³]
554 Scalar injTNH_; // [kg/m³] //computed from NH4Cl
555 Scalar injO2_; // [kg/m³]
556 Scalar injSub_; // [kg/m³]
557 Scalar injBiosusp_; // [kg/m³]
558 Scalar injNaCorr_; // [kg/m³]
559 int numInjections_;
560 std::vector<InjectionProcess> injectionType_;
561
562 // the problem name
563 std::string name_;
564 // the permeability for output
565 std::vector<Scalar> permeability_;
566
567 // timing parameters
568 Scalar time_ = 0.0;
569 Scalar timeStepSize_ = 0.0;
570 int episodeIdx_ = 0;
571 };
572 } // end namespace Dumux
573 // [[/details]]
574 // [[/content]]
575 #endif
576