GCC Code Coverage Report


Directory: ../../../builds/dumux-repositories/
File: /builds/dumux-repositories/dumux/dumux/material/fluidsystems/brineair.hh
Date: 2024-09-21 20:52:54
Exec Total Coverage
Lines: 114 126 90.5%
Functions: 36 39 92.3%
Branches: 130 345 37.7%

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 FluidSystems
10 * \copybrief Dumux::FluidSystems::BrineAir
11 */
12 #ifndef DUMUX_BRINE_AIR_FLUID_SYSTEM_HH
13 #define DUMUX_BRINE_AIR_FLUID_SYSTEM_HH
14
15 #include <array>
16 #include <cassert>
17 #include <iomanip>
18
19 #include <dumux/material/idealgas.hh>
20 #include <dumux/material/fluidstates/adapter.hh>
21 #include <dumux/material/fluidsystems/base.hh>
22 #include <dumux/material/fluidsystems/brine.hh>
23 #include <dumux/material/components/air.hh>
24 #include <dumux/material/components/h2o.hh>
25 #include <dumux/material/components/nacl.hh>
26 #include <dumux/material/binarycoefficients/h2o_air.hh>
27 #include <dumux/material/components/tabulatedcomponent.hh>
28
29 #include <dumux/common/exceptions.hh>
30
31 #include <dumux/io/name.hh>
32
33 #include "brine.hh"
34
35 namespace Dumux {
36 namespace FluidSystems {
37
38 /*!
39 * \ingroup FluidSystems
40 * \brief Policy for the brine-air fluid system
41 */
42 template<bool fastButSimplifiedRelations = false>
43 struct BrineAirDefaultPolicy
44 {
45 static constexpr bool useBrineDensityAsLiquidMixtureDensity() { return fastButSimplifiedRelations;}
46 static constexpr bool useIdealGasDensity() { return fastButSimplifiedRelations; }
47 static constexpr bool useKelvinVaporPressure() { return false; }
48 };
49
50 /*!
51 * \ingroup FluidSystems
52 * \brief A compositional two-phase fluid system with a liquid and a gaseous phase
53 * and \f$H_2O\f$, \f$Air\f$ and \f$S\f$ (dissolved minerals) as components.
54 *
55 * \note This fluidsystem is applied by default with the tabulated version of
56 * water of the IAPWS-formulation.
57 */
58 template <class Scalar,
59 class H2Otype = Components::TabulatedComponent<Components::H2O<Scalar>>,
60 class Policy = BrineAirDefaultPolicy<>>
61 class BrineAir
62 : public Base<Scalar, BrineAir<Scalar, H2Otype, Policy>>
63 {
64 using ThisType = BrineAir<Scalar, H2Otype, Policy>;
65 using IdealGas = Dumux::IdealGas<Scalar>;
66
67 public:
68 //! export the involved components
69 using H2O = H2Otype;
70 using Air = Components::Air<Scalar>;
71 using NaCl = Components::NaCl<Scalar>;
72
73 //! export the underlying brine fluid system for the liquid phase
74 using Brine = Dumux::FluidSystems::Brine<Scalar, H2Otype>;
75
76 //! export the binary coefficients between air and water
77 using H2O_Air = BinaryCoeff::H2O_Air;
78
79 //! the type of parameter cache objects
80 using ParameterCache = NullParameterCache;
81
82 /****************************************
83 * Fluid phase related static parameters
84 ****************************************/
85 static constexpr int numPhases = 2; // one liquid and one gas phase
86 static constexpr int numComponents = 3; // H2O, Air, NaCl
87
88 static constexpr int liquidPhaseIdx = 0; // index of the liquid phase
89 static constexpr int gasPhaseIdx = 1; // index of the gas phase
90
91 static constexpr int phase0Idx = liquidPhaseIdx; // index of the first phase
92 static constexpr int phase1Idx = gasPhaseIdx; // index of the second phase
93
94 // export component indices to indicate the main component
95 // of the corresponding phase at atmospheric pressure 1 bar
96 // and room temperature 20°C:
97 static constexpr int H2OIdx = 0;
98 static constexpr int AirIdx = 1;
99 static constexpr int NaClIdx = 2;
100 static constexpr int comp0Idx = H2OIdx;
101 static constexpr int comp1Idx = AirIdx;
102 static constexpr int comp2Idx = NaClIdx;
103
104 private:
105 struct BrineAdapterPolicy
106 {
107 using FluidSystem = Brine;
108
109 static constexpr int phaseIdx(int brinePhaseIdx) { return liquidPhaseIdx; }
110 static constexpr int compIdx(int brineCompIdx)
111 {
112
10/20
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 6651543 times.
✓ Branch 3 taken 6651543 times.
✓ Branch 4 taken 6651543 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 86316 times.
✓ Branch 7 taken 86316 times.
✓ Branch 8 taken 86316 times.
✓ Branch 9 taken 86316 times.
✓ Branch 10 taken 345264 times.
✓ Branch 11 taken 345264 times.
✓ Branch 12 taken 345264 times.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
21335685 switch (brineCompIdx)
113 {
114 case Brine::H2OIdx: return H2OIdx;
115 14166246 case Brine::NaClIdx: return NaClIdx;
116 default: return 0; // this will never be reached, only needed to suppress compiler warning
117 }
118 }
119 };
120
121 template<class FluidState>
122 using BrineAdapter = FluidStateAdapter<FluidState, BrineAdapterPolicy>;
123
124 public:
125
126 /****************************************
127 * phase related static parameters
128 ****************************************/
129
130 /*!
131 * \brief Return the human readable name of a fluid phase
132 * \param phaseIdx index of the phase
133 */
134 418 static std::string phaseName(int phaseIdx)
135 {
136
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 414 times.
418 assert(0 <= phaseIdx && phaseIdx < numPhases);
137
2/3
✓ Branch 0 taken 207 times.
✓ Branch 1 taken 207 times.
✗ Branch 2 not taken.
418 switch (phaseIdx)
138 {
139 209 case liquidPhaseIdx: return IOName::liquidPhase();
140 209 case gasPhaseIdx: return IOName::gaseousPhase();
141 }
142 DUNE_THROW(Dune::InvalidStateException, "Invalid phase index " << phaseIdx);
143 }
144
145 /*!
146 * \brief Returns whether the fluids are miscible
147 */
148 static constexpr bool isMiscible()
149 { return true; }
150
151 /*!
152 * \brief Return whether a phase is gaseous
153 * \param phaseIdx The index of the fluid phase to consider
154 */
155 static constexpr bool isGas(int phaseIdx)
156 {
157
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 assert(0 <= phaseIdx && phaseIdx < numPhases);
158 return phaseIdx == gasPhaseIdx;
159 }
160
161 /*!
162 * \brief Returns true if and only if a fluid phase is assumed to
163 * be an ideal mixture.
164 *
165 * We define an ideal mixture as a fluid phase where the fugacity
166 * coefficients of all components times the pressure of the phase
167 * are independent on the fluid composition. This assumption is true
168 * if Henry's law and Raoult's law apply. If you are unsure what
169 * this function should return, it is safe to return false. The
170 * only damage done will be (slightly) increased computation times
171 * in some cases.
172 *
173 * \param phaseIdx The index of the fluid phase to consider
174 */
175 static bool isIdealMixture(int phaseIdx)
176 {
177
2/6
✗ Branch 0 not taken.
✓ Branch 1 taken 452423 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 452423 times.
904846 assert(0 <= phaseIdx && phaseIdx < numPhases);
178 // we assume Henry's and Raoult's laws for the water phase and
179 // and no interaction between gas molecules of different
180 // components, so all phases are ideal mixtures!
181 return true;
182 }
183
184 /*!
185 * \brief Returns true if and only if a fluid phase is assumed to
186 * be compressible.
187 *
188 * Compressible means that the partial derivative of the density
189 * to the fluid pressure is always larger than zero.
190 *
191 * \param phaseIdx The index of the fluid phase to consider
192 */
193 static constexpr bool isCompressible(int phaseIdx)
194 {
195 assert(0 <= phaseIdx && phaseIdx < numPhases);
196 // ideal gases are always compressible
197
4/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 1 times.
4 if (phaseIdx == gasPhaseIdx)
198 return true;
199 // let brine decide for the liquid phase...
200 return Brine::isCompressible(Brine::liquidPhaseIdx);
201 }
202
203 /*!
204 * \brief Returns true if and only if a fluid phase is assumed to
205 * be an ideal gas.
206 * \param phaseIdx The index of the fluid phase to consider
207 */
208 static bool isIdealGas(int phaseIdx)
209 {
210 assert(0 <= phaseIdx && phaseIdx < numPhases);
211 // let the fluids decide
212 if (phaseIdx == gasPhaseIdx)
213 return H2O::gasIsIdeal() && Air::gasIsIdeal();
214 return false; // not a gas
215 }
216
217 /*!
218 * \brief Get the main component of a given phase if possible
219 * \param phaseIdx The index of the fluid phase to consider
220 */
221 static constexpr int getMainComponent(int phaseIdx)
222 {
223
3/6
✗ Branch 0 not taken.
✓ Branch 1 taken 30432872 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 22179600 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 26000256 times.
78612728 assert(0 <= phaseIdx && phaseIdx < numPhases);
224
8/8
✓ Branch 0 taken 15216436 times.
✓ Branch 1 taken 15216436 times.
✓ Branch 2 taken 11089800 times.
✓ Branch 3 taken 11089800 times.
✓ Branch 4 taken 13000128 times.
✓ Branch 5 taken 13000128 times.
✓ Branch 6 taken 6002898 times.
✓ Branch 7 taken 6002898 times.
90618524 if (phaseIdx == liquidPhaseIdx)
225 return H2OIdx;
226 else
227 return AirIdx;
228 }
229
230 /****************************************
231 * Component related static parameters
232 ****************************************/
233 /*!
234 * \brief Return the human readable name of a component
235 * \param compIdx The index of the component to consider
236 */
237 36 static std::string componentName(int compIdx)
238 {
239
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 30 times.
36 assert(0 <= compIdx && compIdx < numComponents);
240
3/4
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 10 times.
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
36 switch (compIdx)
241 {
242 12 case H2OIdx: return H2O::name();
243 12 case AirIdx: return Air::name();
244 12 case NaClIdx: return NaCl::name();
245 }
246 DUNE_THROW(Dune::InvalidStateException, "Invalid component index " << compIdx);
247 }
248
249 /*!
250 * \brief Return the molar mass of a component in \f$\mathrm{[kg/mol]}\f$.
251 * \param compIdx The index of the component to consider
252 */
253 206124543 static Scalar molarMass(int compIdx)
254 {
255
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 206124453 times.
206124543 assert(0 <= compIdx && compIdx < numComponents);
256 switch (compIdx)
257 {
258 case H2OIdx: return H2O::molarMass();
259 case AirIdx: return Air::molarMass();
260 case NaClIdx: return NaCl::molarMass();
261 }
262 DUNE_THROW(Dune::InvalidStateException, "Invalid component index " << compIdx);
263 }
264
265 /*!
266 * \brief Vapor pressure of a component \f$\mathrm{[Pa]}\f$.
267 *
268 * \param fluidState The fluid state
269 * \param compIdx The index of the component to consider
270 */
271 template <class FluidState>
272 static Scalar vaporPressure(const FluidState& fluidState, int compIdx)
273 {
274 // The vapor pressure of the water is affected by the
275 // salinity, thus, we forward to the interface of Brine here
276 if (compIdx == H2OIdx)
277 {
278 if (!Policy::useKelvinVaporPressure())
279 return Brine::vaporPressure(BrineAdapter<FluidState>(fluidState), Brine::H2OIdx);
280 else
281 {
282 //additionally taking the influence of the capillary pressure on the vapor pressure, described by Kelvin's equation, into account.
283 const auto t = fluidState.temperature(liquidPhaseIdx);
284 const auto pc = (fluidState.wettingPhase() == (int) liquidPhaseIdx)
285 ? fluidState.pressure(gasPhaseIdx)-fluidState.pressure(liquidPhaseIdx)
286 : fluidState.pressure(liquidPhaseIdx)-fluidState.pressure(gasPhaseIdx);
287 //influence of the capillary pressure on the vapor pressure, the influence of the salt concentration is already taken into account in the brine vapour pressure
288 return Brine::vaporPressure(BrineAdapter<FluidState>(fluidState), Brine::H2OIdx)
289 *exp( -pc / (Brine::molarDensity(fluidState, liquidPhaseIdx) * (Dumux::Constants<Scalar>::R*t)));
290 }
291 }
292 else if (compIdx == NaClIdx)
293 DUNE_THROW(Dune::NotImplemented, "NaCl::vaporPressure(t)");
294 else
295 DUNE_THROW(Dune::NotImplemented, "Invalid component index " << compIdx);
296 }
297
298 /****************************************
299 * thermodynamic relations
300 ****************************************/
301 /*!
302 * \brief Initialize the fluid system's static parameters generically
303 *
304 * If a tabulated H2O component is used, we do our best to create
305 * tables that always work.
306 */
307 static void init()
308 {
309 2 init(/*tempMin=*/273.15,
310 /*tempMax=*/800.0,
311 /*numTemptempSteps=*/200,
312 /*startPressure=*/-10,
313 /*endPressure=*/20e6,
314 /*pressureSteps=*/200);
315 }
316
317 /*!
318 * \brief Initialize the fluid system's static parameters using
319 * problem specific temperature and pressure ranges
320 *
321 * \param tempMin The minimum temperature used for tabulation of water \f$\mathrm{[K]}\f$
322 * \param tempMax The maximum temperature used for tabulation of water \f$\mathrm{[K]}\f$
323 * \param nTemp The number of ticks on the temperature axis of the table of water
324 * \param pressMin The minimum pressure used for tabulation of water \f$\mathrm{[Pa]}\f$
325 * \param pressMax The maximum pressure used for tabulation of water \f$\mathrm{[Pa]}\f$
326 * \param nPress The number of ticks on the pressure axis of the table of water
327 */
328 8 static void init(Scalar tempMin, Scalar tempMax, unsigned nTemp,
329 Scalar pressMin, Scalar pressMax, unsigned nPress)
330 {
331 8 std::cout << "The brine-air fluid system was configured with the following policy:\n";
332 16 std::cout << " - use brine density as liquid mixture density: " << std::boolalpha << Policy::useBrineDensityAsLiquidMixtureDensity() << "\n";
333 16 std::cout << " - use ideal gas density: " << std::boolalpha << Policy::useIdealGasDensity() << std::endl;
334
335 if (H2O::isTabulated)
336 H2O::init(tempMin, tempMax, nTemp, pressMin, pressMax, nPress);
337 8 }
338
339 using Base<Scalar, ThisType>::density;
340 /*!
341 * \brief Given a phase's composition, temperature, pressure, and
342 * the partial pressures of all components, return its
343 * density \f$\mathrm{[kg/m^3]}\f$.
344 *
345 * \param fluidState the fluid state
346 * \param phaseIdx index of the phase
347 *
348 * Equation given in:
349 * - Batzle & Wang (1992) \cite batzle1992
350 * - cited by: Bachu & Adams (2002)
351 * "Equations of State for basin geofluids" \cite adams2002
352 */
353 template <class FluidState>
354 4607002 static Scalar density(const FluidState &fluidState, int phaseIdx)
355 {
356
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4606998 times.
4607002 assert(0 <= phaseIdx && phaseIdx < numPhases);
357
358
2/2
✓ Branch 0 taken 2303497 times.
✓ Branch 1 taken 2303497 times.
4607002 const auto T = fluidState.temperature(phaseIdx);
359
2/2
✓ Branch 0 taken 2303497 times.
✓ Branch 1 taken 2303497 times.
4607002 const auto p = fluidState.pressure(phaseIdx);
360
361
2/2
✓ Branch 0 taken 2303499 times.
✓ Branch 1 taken 2303499 times.
4607002 if (phaseIdx == liquidPhaseIdx)
362 {
363 // assume pure brine
364 if (Policy::useBrineDensityAsLiquidMixtureDensity())
365 4 return Brine::density(BrineAdapter<FluidState>(fluidState), Brine::liquidPhaseIdx);
366
367 // assume one molecule of gas replaces one "brine" molecule
368 else
369 4606998 return Brine::molarDensity(BrineAdapter<FluidState>(fluidState), Brine::liquidPhaseIdx)
370 2303499 *(H2O::molarMass()*fluidState.moleFraction(liquidPhaseIdx, H2OIdx)
371 2303499 + NaCl::molarMass()*fluidState.moleFraction(liquidPhaseIdx, NaClIdx)
372 4606996 + Air::molarMass()*fluidState.moleFraction(liquidPhaseIdx, AirIdx));
373 }
374 else if (phaseIdx == phase1Idx)
375 {
376 // for the gas phase assume an ideal gas
377 if (Policy::useIdealGasDensity())
378 2 return IdealGas::density(fluidState.averageMolarMass(phase1Idx), T, p);
379
380 // if useComplexRelations = true, compute density. NaCl is assumed
381 // not to be present in gas phase, NaCl has only solid interfaces implemented
382 4606996 return H2O::gasDensity(T, fluidState.partialPressure(phase1Idx, H2OIdx))
383 6910493 + Air::gasDensity(T, fluidState.partialPressure(phase1Idx, AirIdx));
384 }
385 else
386 DUNE_THROW(Dune::InvalidStateException, "Invalid phase index " << phaseIdx);
387 }
388
389 using Base<Scalar, ThisType>::molarDensity;
390 //! \copydoc Base<Scalar,ThisType>::molarDensity(const FluidState&,int)
391 template <class FluidState>
392 4607002 static Scalar molarDensity(const FluidState& fluidState, int phaseIdx)
393 {
394
2/2
✓ Branch 0 taken 2303499 times.
✓ Branch 1 taken 2303499 times.
4607002 if (phaseIdx == liquidPhaseIdx)
395 6910503 return Brine::molarDensity(BrineAdapter<FluidState>(fluidState), Brine::liquidPhaseIdx);
396
1/2
✓ Branch 0 taken 2303499 times.
✗ Branch 1 not taken.
2303501 else if (phaseIdx == phase1Idx)
397 {
398 2303501 const Scalar T = fluidState.temperature(phaseIdx);
399
400 // for the gas phase assume an ideal gas
401 if (Policy::useIdealGasDensity())
402 2 return IdealGas::molarDensity(T, fluidState.pressure(phaseIdx));
403
404 // if useComplexRelations = true, compute density. NaCl is assumed
405 // not to be present in gas phase, NaCl has only solid interfaces implemented
406 4606996 return H2O::gasMolarDensity(T, fluidState.partialPressure(phase1Idx, H2OIdx))
407 6910493 + Air::gasMolarDensity(T, fluidState.partialPressure(phase1Idx, AirIdx));
408 }
409 else
410 DUNE_THROW(Dune::InvalidStateException, "Invalid phase index " << phaseIdx);
411 }
412
413 using Base<Scalar, ThisType>::viscosity;
414 /*!
415 * \brief Calculate the dynamic viscosity of a fluid phase \f$\mathrm{[Pa*s]}\f$
416 *
417 * \param fluidState An arbitrary fluid state
418 * \param phaseIdx The index of the fluid phase to consider
419 *
420 * \note For the viscosity of the phases the contribution of the minor
421 * component is neglected. This contribution is probably not big, but somebody
422 * would have to find out its influence.
423 */
424 template <class FluidState>
425 4607002 static Scalar viscosity(const FluidState& fluidState, int phaseIdx)
426 {
427
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4606998 times.
4607002 assert(0 <= phaseIdx && phaseIdx < numPhases);
428
429
2/2
✓ Branch 0 taken 2303499 times.
✓ Branch 1 taken 2303499 times.
4607002 if (phaseIdx == liquidPhaseIdx)
430 4607002 return Brine::viscosity(BrineAdapter<FluidState>(fluidState), Brine::liquidPhaseIdx);
431 else
432 6910495 return Air::gasViscosity(fluidState.temperature(phaseIdx), fluidState.pressure(phaseIdx));
433 }
434
435 using Base<Scalar, ThisType>::fugacityCoefficient;
436 /*!
437 * \brief Returns the fugacity coefficient \f$\mathrm{[-]}\f$ of a component in a
438 * phase.
439 * \param fluidState The fluid state
440 * \param phaseIdx Index of the phase
441 * \param compIdx Index of the component
442 *
443 * The fugacity coefficient \f$\mathrm{\phi^\kappa_\alpha}\f$ of
444 * component \f$\mathrm{\kappa}\f$ in phase \f$\mathrm{\alpha}\f$ is connected to
445 * the fugacity \f$\mathrm{f^\kappa_\alpha}\f$ and the component's mole
446 * fraction \f$\mathrm{x^\kappa_\alpha}\f$ by means of the relation
447 *
448 * \f[
449 f^\kappa_\alpha = \phi^\kappa_\alpha\;x^\kappa_\alpha\;p_\alpha
450 \f]
451 * where \f$\mathrm{p_\alpha}\f$ is the pressure of the fluid phase.
452 *
453 * For liquids with very low miscibility this boils down to the
454 * Henry constant for the solutes and the saturated vapor pressure
455 * both divided by phase pressure.
456 */
457 template <class FluidState>
458 13821006 static Scalar fugacityCoefficient(const FluidState& fluidState, int phaseIdx, int compIdx)
459 {
460
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 13820994 times.
13821006 assert(0 <= phaseIdx && phaseIdx < numPhases);
461
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 13820994 times.
13821006 assert(0 <= compIdx && compIdx < numComponents);
462
463
2/2
✓ Branch 0 taken 6910491 times.
✓ Branch 1 taken 6910491 times.
13821006 Scalar T = fluidState.temperature(phaseIdx);
464
2/2
✓ Branch 0 taken 6910491 times.
✓ Branch 1 taken 6910491 times.
13821006 Scalar p = fluidState.pressure(phaseIdx);
465
466
2/2
✓ Branch 0 taken 6910497 times.
✓ Branch 1 taken 6910497 times.
13821006 if (phaseIdx == gasPhaseIdx)
467 return 1.0;
468
469 else if (phaseIdx == liquidPhaseIdx)
470 {
471 // TODO: Should we use the vapor pressure of the mixture (brine) here?
472 // The presence of NaCl lowers the vapor pressure, thus, we would
473 // expect the fugacity coefficient to be lower as well. However,
474 // with the fugacity coefficient being dependent on the salinity,
475 // the equation system for the phase equilibria becomes non-linear
476 // and our constraint solvers assume linear system of equations.
477
2/2
✓ Branch 0 taken 2303499 times.
✓ Branch 1 taken 4606998 times.
6910503 if (compIdx == H2OIdx)
478 2303501 return H2O::vaporPressure(T)/p;
479
480
2/2
✓ Branch 0 taken 2303499 times.
✓ Branch 1 taken 2303499 times.
4607002 else if (compIdx == AirIdx)
481 4607002 return BinaryCoeff::H2O_Air::henry(T)/p;
482
483 // we assume nacl always stays in the liquid phase
484 else
485 return 0.0;
486 }
487
488 DUNE_THROW(Dune::InvalidStateException, "Invalid phase index " << phaseIdx);
489 }
490
491 using Base<Scalar, ThisType>::diffusionCoefficient;
492 //! \copydoc Base<Scalar,ThisType>::diffusionCoefficient(const FluidState&,int,int)
493 template <class FluidState>
494 24 static Scalar diffusionCoefficient(const FluidState &fluidState,
495 int phaseIdx,
496 int compIdx)
497 {
498
7/16
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
✓ Branch 11 taken 12 times.
✗ Branch 12 not taken.
✓ Branch 15 taken 12 times.
✗ Branch 16 not taken.
✓ Branch 18 taken 12 times.
✗ Branch 19 not taken.
✓ Branch 21 taken 12 times.
✗ Branch 22 not taken.
✓ Branch 23 taken 12 times.
✗ Branch 24 not taken.
✗ Branch 26 not taken.
✓ Branch 27 taken 12 times.
✗ Branch 29 not taken.
✗ Branch 30 not taken.
264 DUNE_THROW(Dune::NotImplemented, "Diffusion coefficients");
499 }
500
501 using Base<Scalar, ThisType>::binaryDiffusionCoefficient;
502 //! \copydoc Base<Scalar,ThisType>::binaryDiffusionCoefficient(const FluidState&,int,int,int)
503 template <class FluidState>
504 9231008 static Scalar binaryDiffusionCoefficient(const FluidState& fluidState,
505 int phaseIdx,
506 int compIIdx,
507 int compJIdx)
508 {
509
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9230972 times.
9231008 assert(0 <= phaseIdx && phaseIdx < numPhases);
510
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9230972 times.
9231008 assert(0 <= compIIdx && compIIdx < numComponents);
511
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9230972 times.
9231008 assert(0 <= compJIdx && compJIdx < numComponents);
512
513
2/2
✓ Branch 0 taken 2320445 times.
✓ Branch 1 taken 6910491 times.
9231008 const auto T = fluidState.temperature(phaseIdx);
514
2/2
✓ Branch 0 taken 2320445 times.
✓ Branch 1 taken 6910491 times.
9231008 const auto p = fluidState.pressure(phaseIdx);
515
516
2/2
✓ Branch 0 taken 2320457 times.
✓ Branch 1 taken 6910515 times.
9231008 if (compIIdx > compJIdx)
517 2320469 std::swap(compIIdx, compJIdx);
518
519
2/2
✓ Branch 0 taken 4607012 times.
✓ Branch 1 taken 4623960 times.
9231008 if (phaseIdx == liquidPhaseIdx)
520 {
521
4/4
✓ Branch 0 taken 4607004 times.
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 2303501 times.
✓ Branch 3 taken 2303503 times.
4607030 if(compIIdx == H2OIdx && compJIdx == AirIdx)
522 4607010 return H2O_Air::liquidDiffCoeff(T, p);
523
4/4
✓ Branch 0 taken 2303503 times.
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 2303501 times.
✓ Branch 3 taken 2 times.
2303525 else if (compIIdx == H2OIdx && compJIdx == NaClIdx)
524 4607010 return Brine::binaryDiffusionCoefficient(BrineAdapter<FluidState>(fluidState), Brine::liquidPhaseIdx, Brine::H2OIdx, Brine::NaClIdx);
525 else
526
9/20
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
✓ Branch 11 taken 10 times.
✗ Branch 12 not taken.
✓ Branch 16 taken 10 times.
✗ Branch 17 not taken.
✓ Branch 20 taken 10 times.
✗ Branch 21 not taken.
✓ Branch 24 taken 10 times.
✗ Branch 25 not taken.
✓ Branch 27 taken 10 times.
✗ Branch 28 not taken.
✓ Branch 30 taken 10 times.
✗ Branch 31 not taken.
✓ Branch 32 taken 10 times.
✗ Branch 33 not taken.
✗ Branch 35 not taken.
✓ Branch 36 taken 10 times.
✗ Branch 38 not taken.
✗ Branch 39 not taken.
280 DUNE_THROW(Dune::NotImplemented, "Binary diffusion coefficient of components "
527 << compIIdx << " and " << compJIdx
528 << " in phase " << phaseIdx);
529 }
530 else if (phaseIdx == gasPhaseIdx)
531 {
532
4/4
✓ Branch 0 taken 2320455 times.
✓ Branch 1 taken 2303505 times.
✓ Branch 2 taken 2320449 times.
✓ Branch 3 taken 6 times.
4623978 if (compIIdx == H2OIdx && compJIdx == AirIdx)
533 4640906 return H2O_Air::gasDiffCoeff(T, p);
534
535 // NaCl is expected to never be present in the gas phase. we need to
536 // return a diffusion coefficient that does not case numerical problems.
537 // We choose a very small value here.
538
4/4
✓ Branch 0 taken 2303503 times.
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 2303501 times.
2303525 else if (compIIdx == AirIdx && compJIdx == NaClIdx)
539 return 1e-12;
540
541 else
542
9/20
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
✓ Branch 11 taken 10 times.
✗ Branch 12 not taken.
✓ Branch 16 taken 10 times.
✗ Branch 17 not taken.
✓ Branch 20 taken 10 times.
✗ Branch 21 not taken.
✓ Branch 24 taken 10 times.
✗ Branch 25 not taken.
✓ Branch 27 taken 10 times.
✗ Branch 28 not taken.
✓ Branch 30 taken 10 times.
✗ Branch 31 not taken.
✓ Branch 32 taken 10 times.
✗ Branch 33 not taken.
✗ Branch 35 not taken.
✓ Branch 36 taken 10 times.
✗ Branch 38 not taken.
✗ Branch 39 not taken.
280 DUNE_THROW(Dune::NotImplemented, "Binary diffusion coefficient of components "
543 << compIIdx << " and " << compJIdx
544 << " in phase " << phaseIdx);
545 }
546
547 DUNE_THROW(Dune::InvalidStateException, "Invalid phase index " << phaseIdx);
548 }
549
550 using Base<Scalar, ThisType>::enthalpy;
551 /*!
552 * \brief Given a phase's composition, temperature and pressure,
553 * return its specific enthalpy \f$\mathrm{[J/kg]}\f$.
554 * \param fluidState The fluid state
555 * \param phaseIdx The index of the phase
556 *
557 * See:
558 * Class 2000
559 * Theorie und numerische Modellierung nichtisothermer Mehrphasenprozesse in NAPL-kontaminierten porösen Medien
560 * Chapter 2.1.13 Innere Energie, Wäremekapazität, Enthalpie \cite A3:class:2001
561 *
562 * Formula (2.42):
563 * the specific enthalpy of a gas phase result from the sum of (enthalpies*mass fraction) of the components
564 * For the calculation of enthalpy of brine we refer to (Michaelides 1981)
565 *
566 * \note For the phase enthalpy the contribution of gas-molecules in the liquid phase
567 * is neglected. This contribution is probably not big. Somebody would have to
568 * find out the enthalpy of solution for this system. ...
569 */
570 template <class FluidState>
571 172640 static Scalar enthalpy(const FluidState& fluidState, int phaseIdx)
572 {
573
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 172636 times.
172640 assert(0 <= phaseIdx && phaseIdx < numPhases);
574
575
2/2
✓ Branch 0 taken 86316 times.
✓ Branch 1 taken 86316 times.
172640 const Scalar T = fluidState.temperature(phaseIdx);
576
2/2
✓ Branch 0 taken 86316 times.
✓ Branch 1 taken 86316 times.
172640 const Scalar p = fluidState.pressure(phaseIdx);
577
578
2/2
✓ Branch 0 taken 86318 times.
✓ Branch 1 taken 86318 times.
172640 if (phaseIdx == liquidPhaseIdx)
579 172640 return Brine::enthalpy(BrineAdapter<FluidState>(fluidState), Brine::liquidPhaseIdx);
580 else if (phaseIdx == gasPhaseIdx)
581 {
582 // This assumes NaCl not to be present in the gas phase
583 86320 const Scalar XAir = fluidState.massFraction(gasPhaseIdx, AirIdx);
584 86320 const Scalar XH2O = fluidState.massFraction(gasPhaseIdx, H2OIdx);
585 86320 return XH2O*H2O::gasEnthalpy(T, p) + XAir*Air::gasEnthalpy(T, p);
586 }
587
588 DUNE_THROW(Dune::InvalidStateException, "Invalid phase index " << phaseIdx);
589 }
590
591 /*!
592 * \brief Returns the specific enthalpy \f$\mathrm{[J/kg]}\f$ of a component in a specific phase
593 * \param fluidState The fluid state
594 * \param phaseIdx The index of the phase
595 * \param componentIdx The index of the component
596 */
597 template <class FluidState>
598 33896 static Scalar componentEnthalpy(const FluidState& fluidState, int phaseIdx, int componentIdx)
599 {
600
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 33896 times.
33896 const Scalar T = fluidState.temperature(gasPhaseIdx);
601
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 33896 times.
33896 const Scalar p = fluidState.pressure(gasPhaseIdx);
602
603
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 33896 times.
33896 if (phaseIdx == liquidPhaseIdx)
604 DUNE_THROW(Dune::NotImplemented, "The component enthalpies in the liquid phase are not implemented.");
605
606
1/2
✓ Branch 0 taken 33896 times.
✗ Branch 1 not taken.
33896 else if (phaseIdx == gasPhaseIdx)
607 {
608
2/2
✓ Branch 0 taken 16948 times.
✓ Branch 1 taken 16948 times.
33896 if (componentIdx == H2OIdx)
609 16948 return H2O::gasEnthalpy(T, p);
610
1/2
✓ Branch 0 taken 16948 times.
✗ Branch 1 not taken.
16948 else if (componentIdx == AirIdx)
611 33896 return Air::gasEnthalpy(T, p);
612 else if (componentIdx == NaClIdx)
613 DUNE_THROW(Dune::InvalidStateException, "Implementation assumes NaCl not to be present in gas phase");
614 DUNE_THROW(Dune::InvalidStateException, "Invalid component index " << componentIdx);
615 }
616 DUNE_THROW(Dune::InvalidStateException, "Invalid phase index " << phaseIdx);
617 }
618
619 using Base<Scalar, ThisType>::thermalConductivity;
620 /*!
621 * \brief Thermal conductivity of a fluid phase \f$\mathrm{[W/(m K)]}\f$.
622 * \param fluidState An arbitrary fluid state
623 * \param phaseIdx The index of the fluid phase to consider
624 *
625 * \note We assume an ideal mixture for the gas-phase thermal conductivity, as a first approximation.
626 * In porous media, gas-phase thermal conductivities are negligible, as they are
627 * orders of magnitude lower than the thermal conductivity in solid and liquids (gas: 0.0x compared to solid: x.).
628 * However, moisture can have a significant influce on the thermal conductivity of moist air, see e.g. \cite Beirao2012,
629 * which could be relevant for free-flow systems.
630 */
631 template <class FluidState>
632 189588 static Scalar thermalConductivity(const FluidState& fluidState, int phaseIdx)
633 {
634
2/2
✓ Branch 0 taken 86318 times.
✓ Branch 1 taken 103266 times.
189588 if (phaseIdx == liquidPhaseIdx)
635 172640 return Brine::thermalConductivity(BrineAdapter<FluidState>(fluidState), Brine::liquidPhaseIdx);
636 // This assumes NaCl not to be present in the gas phase
637
1/2
✓ Branch 0 taken 103266 times.
✗ Branch 1 not taken.
103268 else if (phaseIdx == gasPhaseIdx)
638 309796 return Air::gasThermalConductivity(fluidState.temperature(phaseIdx), fluidState.pressure(phaseIdx)) * fluidState.massFraction(gasPhaseIdx, AirIdx)
639 309796 + H2O::gasThermalConductivity(fluidState.temperature(phaseIdx), fluidState.pressure(phaseIdx)) * fluidState.massFraction(gasPhaseIdx, H2OIdx);
640
641 DUNE_THROW(Dune::InvalidStateException, "Invalid phase index " << phaseIdx);
642 }
643
644 using Base<Scalar, ThisType>::heatCapacity;
645 /*!
646 * \brief Specific isobaric heat capacity of a fluid phase.
647 * \f$\mathrm{[J/(kg*K)}\f$.
648 * \param fluidState An arbitrary fluid state
649 * \param phaseIdx The index of the fluid phase to consider
650 *
651 * \note We assume an ideal mixture for the gas-phase specific isobaric heat capacity, as a first approximation.
652 * In porous media, gas-phase heat capacities are, due to the usually low densities of gases, negligible anyway.
653 * A better implementation might be relevant for free-flow systems.
654 */
655 template <class FluidState>
656 4 static Scalar heatCapacity(const FluidState &fluidState, int phaseIdx)
657 {
658 4 const Scalar T = fluidState.temperature(phaseIdx);
659 4 const Scalar p = fluidState.pressure(phaseIdx);
660
661 4 if (phaseIdx == liquidPhaseIdx)
662 4 return Brine::heatCapacity(BrineAdapter<FluidState>(fluidState), Brine::liquidPhaseIdx);
663
664 // We assume NaCl not to be present in the gas phase here
665 2 else if (phaseIdx == gasPhaseIdx)
666 2 return Air::gasHeatCapacity(T, p)*fluidState.massFraction(gasPhaseIdx, AirIdx)
667 2 + H2O::gasHeatCapacity(T, p)*fluidState.massFraction(gasPhaseIdx, H2OIdx);
668
669 DUNE_THROW(Dune::InvalidStateException, "Invalid phase index " << phaseIdx);
670 }
671 };
672
673 } // end namespace FluidSystems
674 } // end namespace Dumux
675
676 #endif
677