OGS
PhaseTransition.cpp
Go to the documentation of this file.
1
10#include "PhaseTransition.h"
11
13
14namespace
15{
17 std::map<int, std::shared_ptr<MaterialPropertyLib::Medium>> const& media,
18 std::string const& phase_name)
19{
20 // Always the first (begin) medium that holds fluid phases.
21 auto const& medium = media.begin()->second;
22 return medium->phase(phase_name).numberOfComponents();
23}
24
26 std::map<int, std::shared_ptr<MaterialPropertyLib::Medium>> const& media,
27 std::string const& phase_name,
29{
30 // It is always the first (begin) medium that holds fluid phases.
31 auto const& medium = media.begin()->second;
32 auto const& phase = medium->phase(phase_name);
33
34 // find the component for which the property 'property_type' is defined
35 for (std::size_t c = 0; c < phase.numberOfComponents(); c++)
36 {
37 if (phase.component(c).hasProperty(property_type))
38 {
39 return c;
40 }
41 }
42
43 // A lot of checks can (and should) be done to make sure that the right
44 // components with the right properties are used. For example, the names
45 // of the components can be compared to check that the name of the
46 // evaporable component does not also correspond to the name of the
47 // solute.
48
50 "PhaseTransitionModel: findComponentIndex() could not find the "
51 "specified property type '{:s}' in phase '{:s}'.",
53 phase_name);
54}
55} // namespace
56
57namespace ProcessLib::TH2M
58{
59namespace ConstitutiveRelations
60{
62 std::map<int, std::shared_ptr<MaterialPropertyLib::Medium>> const& media)
63 : PhaseTransitionModel(media),
64 n_components_gas_{numberOfComponents(media, "Gas")},
65 // Identifies and initialises the indices of the various components via
66 // their properties
67 gas_phase_vapour_component_index_{findComponentIndex(
68 media, "Gas", MaterialPropertyLib::PropertyType::vapour_pressure)},
69 // Dry air component is complement of vapour component index
70 gas_phase_dry_air_component_index_{1 - gas_phase_vapour_component_index_},
71 // The solute is the component of the liquid phase which has been assigned
72 // the property `henry_coefficient'.
73 liquid_phase_solute_component_index_{findComponentIndex(
74 media, "AqueousLiquid",
75 MaterialPropertyLib::PropertyType::henry_coefficient)},
76 // The solvent is again the bitwise complement of the solute component
77 liquid_phase_solvent_component_index_{
78 1 - liquid_phase_solute_component_index_}
79{
80 DBUG("Create PhaseTransition constitutive model.");
81
82 if (n_components_gas_ != 2)
83 {
85 "The current implementation of PhaseTransitionModelEvaporation "
86 "requires the specification of exactly two components in the "
87 "gas "
88 "phase.");
89 }
90
91 // It is always the first (begin) medium that holds fluid phases.
92 auto const medium = media.begin()->second;
93 auto const& gas_phase = medium->phase("Gas");
94 auto const& liquid_phase = medium->phase("AqueousLiquid");
95
96 // check for minimum requirement definitions in media object
97 std::array const required_vapour_component_properties = {
102
103 std::array const required_dry_air_component_properties = {
106
107 std::array const required_solute_component_properties = {
111
112 std::array const required_solvent_component_properties = {
114
115 std::array const required_gas_properties = {MaterialPropertyLib::density,
117
118 std::array const required_liquid_properties = {
120
121 checkRequiredProperties(
122 gas_phase.component(gas_phase_vapour_component_index_),
123 required_vapour_component_properties);
124 checkRequiredProperties(
125 gas_phase.component(gas_phase_dry_air_component_index_),
126 required_dry_air_component_properties);
127 checkRequiredProperties(
128 liquid_phase.component(liquid_phase_solute_component_index_),
129 required_solute_component_properties);
130 checkRequiredProperties(
131 liquid_phase.component(liquid_phase_solvent_component_index_),
132 required_solvent_component_properties);
133 checkRequiredProperties(gas_phase, required_gas_properties);
134 checkRequiredProperties(liquid_phase, required_liquid_properties);
135}
136
138 MediaData const& media_data,
139 GasPressureData const& p_GR,
140 CapillaryPressureData const& p_cap,
141 TemperatureData const& T_data,
142 PureLiquidDensityData const& rho_W_LR,
143 ViscosityData& viscosity_data,
144 EnthalpyData& enthalpy_data,
145 MassMoleFractionsData& mass_mole_fractions_data,
146 FluidDensityData& fluid_density_data,
147 VapourPartialPressureData& vapour_pressure_data,
148 ConstituentDensityData& constituent_density_data,
149 PhaseTransitionData& cv) const
150{
152
153 // primary variables
154 auto const pGR = p_GR();
155 auto const pCap = p_cap();
156 auto const T = T_data.T;
157 variables.gas_phase_pressure = pGR;
158 variables.capillary_pressure = pCap;
159 variables.temperature = T;
160
161 auto const& liquid_phase = media_data.liquid;
162 auto const& gas_phase = media_data.gas;
163
165
166 // identify vapour and air components for convenient access
167 auto const& vapour_component =
169 auto const& dry_air_component =
170 gas_phase.component(gas_phase_dry_air_component_index_);
171
172 // specific latent heat (of evaporation)
173 const auto dh_evap =
174 vapour_component
176 .template value<double>(variables, x_t.x, x_t.t, x_t.dt);
177
178 // molar mass of evaporating component
179 auto const M_W =
180 vapour_component.property(MaterialPropertyLib::PropertyType::molar_mass)
181 .template value<double>(variables, x_t.x, x_t.t, x_t.dt);
182
183 // provide evaporation enthalpy and molar mass of the evaporating
184 // component in the variable array
185 variables.enthalpy_of_evaporation = dh_evap;
186 variables.molar_mass = M_W;
187
188 // vapour pressure over flat interface
189 const auto p_vap_flat =
190 vapour_component
192 .template value<double>(variables, x_t.x, x_t.t, x_t.dt);
193
194 const auto dp_vap_flat_dT =
195 vapour_component
197 .template dValue<double>(variables,
199 x_t.x, x_t.t, x_t.dt);
200
201 // molar mass of dry air component
202 auto const M_C =
203 dry_air_component
205 .template value<double>(variables, x_t.x, x_t.t, x_t.dt);
206
207 // Water pressure is passed to the VariableArray in order to calculate
208 // the water density.
209 auto const pLR = pGR - pCap;
210 variables.liquid_phase_pressure = pLR;
211
212 // Kelvin-Laplace correction for menisci
213 const double K =
214 pCap > 0. ? std::exp(-pCap * M_W / rho_W_LR() / R / T) : 1.;
215 const double dK_dT =
216 pCap > 0. ? pCap * M_W / rho_W_LR() / R / T / T * K : 0;
217 const double dK_dpCap =
218 pCap > 0. ? -M_W / rho_W_LR() / R / T * K
219 : 0.; // rho_W_LR is treated as a constant here. However, the
220 // resulting errors are very small and can be ignored.
221
222 // vapour pressure inside porespace (== water partial pressure in gas
223 // phase)
224 vapour_pressure_data.pWGR = p_vap_flat * K;
225 auto const dpWGR_dT = dp_vap_flat_dT * K + p_vap_flat * dK_dT;
226 auto const dpWGR_dpCap = p_vap_flat * dK_dpCap;
227
228 // gas phase molar fractions
229 auto const xnWG_min =
230 1.e-12; // Magic number; prevents the mass fraction of a component
231 // from ever becoming zero (which would cause the partial
232 // density to disappear and thus one of the Laplace terms
233 // of the mass balance on the diagonal of the local element
234 // matrix to be zero). The value is simply made up, seems
235 // reasonable.
236 cv.xnWG =
237 std::clamp(vapour_pressure_data.pWGR / pGR, xnWG_min, 1. - xnWG_min);
238 mass_mole_fractions_data.xnCG = 1. - cv.xnWG;
239
240 // gas phase molar fraction derivatives
241 auto const dxnWG_dpGR = -vapour_pressure_data.pWGR / pGR / pGR;
242 auto const dxnWG_dpCap = dpWGR_dpCap / pGR;
243 auto const dxnWG_dT = dpWGR_dT / pGR;
244
245 // molar mass of the gas phase as a mixture of 'air' and vapour
246 auto const MG = mass_mole_fractions_data.xnCG * M_C + cv.xnWG * M_W;
247 variables.molar_mass = MG;
248
249 // gas phase mass fractions
250 cv.xmWG = cv.xnWG * M_W / MG;
251 mass_mole_fractions_data.xmCG = 1. - cv.xmWG;
252
253 auto const dxn_dxm_conversion = M_W * M_C / MG / MG;
254 // gas phase mass fraction derivatives
255 cv.dxmWG_dpGR = dxnWG_dpGR * dxn_dxm_conversion;
256 cv.dxmWG_dpCap = dxnWG_dpCap * dxn_dxm_conversion;
257 cv.dxmWG_dT = dxnWG_dT * dxn_dxm_conversion;
258
259 // density of overall gas phase
260 fluid_density_data.rho_GR =
262 .template value<double>(variables, x_t.x, x_t.t, x_t.dt);
263
264 // derivatives of average molar mass of the gas phase
265 auto const dMG = M_W - M_C;
266 auto const dMG_dpGR = dxnWG_dpGR * dMG;
267
268 variables.molar_mass_derivative = dMG_dpGR;
269
270 // Derivatives of the density of the (composite gas phase) and the
271 // partial densities of its components. The density of the mixture can
272 // be obtained via the property 'IdealGasLawBinaryMixture', for this
273 // purpose the derivatives of the mean molar mass are passed in each
274 // case via the variable_array.
275 cv.drho_GR_dp_GR =
277 .template dValue<double>(
279 x_t.x, x_t.t, x_t.dt);
280
281 auto const dMG_dpCap = dxnWG_dpCap * dMG;
282 variables.molar_mass_derivative = dMG_dpCap;
283 cv.drho_GR_dp_cap =
285 .template dValue<double>(
287 x_t.x, x_t.t, x_t.dt);
288
289 auto const dMG_dT = dxnWG_dT * dMG;
290 variables.molar_mass_derivative = dMG_dT;
291 cv.drho_GR_dT =
293 .template dValue<double>(variables,
295 x_t.x, x_t.t, x_t.dt);
296
297 // The derivatives of the partial densities of the gas phase are
298 // hard-coded (they should remain so, as they are a fundamental part of
299 // this evaporation model). By outsourcing the derivatives of the phase
300 // density to the MPL, a constant phase density can also be assumed, the
301 // derivatives of the partial densities are then unaffected and the
302 // model is still consistent.
303 constituent_density_data.rho_C_GR =
304 mass_mole_fractions_data.xmCG * fluid_density_data.rho_GR;
305 constituent_density_data.rho_W_GR = cv.xmWG * fluid_density_data.rho_GR;
306
307 // 'Air'-component partial density derivatives
308 cv.drho_C_GR_dp_GR = mass_mole_fractions_data.xmCG * cv.drho_GR_dp_GR -
309 cv.dxmWG_dpGR * fluid_density_data.rho_GR;
310 cv.drho_C_GR_dp_cap = mass_mole_fractions_data.xmCG * cv.drho_GR_dp_cap -
311 cv.dxmWG_dpCap * fluid_density_data.rho_GR;
312 cv.drho_C_GR_dT = mass_mole_fractions_data.xmCG * cv.drho_GR_dT -
313 cv.dxmWG_dT * fluid_density_data.rho_GR;
314
315 // Vapour-component partial density derivatives
316 cv.drho_W_GR_dp_GR =
317 cv.xmWG * cv.drho_GR_dp_GR + cv.dxmWG_dpGR * fluid_density_data.rho_GR;
319 cv.dxmWG_dpCap * fluid_density_data.rho_GR;
320 cv.drho_W_GR_dT =
321 cv.xmWG * cv.drho_GR_dT + cv.dxmWG_dT * fluid_density_data.rho_GR;
322
323 // specific heat capacities of dry air and vapour
324 auto const cpCG =
325 dry_air_component
327 .template value<double>(variables, x_t.x, x_t.t, x_t.dt);
328 auto const cpWG =
329 vapour_component
331 .template value<double>(variables, x_t.x, x_t.t, x_t.dt);
332
333 // specific enthalpy of dry air and vapour components
334 cv.hCG = cpCG * T;
335 cv.hWG = cpWG * T + dh_evap;
336
337 // specific enthalpy of gas phase
338 enthalpy_data.h_G =
339 mass_mole_fractions_data.xmCG * cv.hCG + cv.xmWG * cv.hWG;
340
341 // specific inner energies of gas phase
342 cv.uG = enthalpy_data.h_G - pGR / fluid_density_data.rho_GR;
343
344 // diffusion
345 auto const tortuosity =
346 media_data.medium
348 .template value<double>(variables, x_t.x, x_t.t, x_t.dt);
349
350 auto const D_W_G_m =
351 vapour_component.property(MaterialPropertyLib::PropertyType::diffusion)
352 .template value<double>(variables, x_t.x, x_t.t, x_t.dt);
354 tortuosity * D_W_G_m; // Note here that D_W_G = D_C_G.
355
356 variables.molar_fraction = mass_mole_fractions_data.xnCG;
357
358 // gas phase viscosity
359 viscosity_data.mu_GR =
361 .template value<double>(variables, x_t.x, x_t.t, x_t.dt);
362
363 // Dissolution part -- Liquid phase properties
364 // -------------------------------------------
365
366 // Reference to the gas component dissolved in the liquid phase
367 auto const& solute_component =
368 liquid_phase.component(liquid_phase_solute_component_index_);
369
370 // The amount of dissolved gas is described by Henry's law. If no
371 // dissolution is intended, the user must define the Henry coefficient
372 // as 'constant 0'.
373 //
374 // Henry-Coefficient and derivatives
375 auto const H =
376 solute_component
378 .template value<double>(variables, x_t.x, x_t.t, x_t.dt);
379
380 auto const dH_dT =
381 solute_component
383 .template dValue<double>(variables,
385 x_t.x, x_t.t, x_t.dt);
386 auto const dH_dpGR =
387 solute_component
389 .template dValue<double>(
391 x_t.x, x_t.t, x_t.dt);
392
393 // Concentration of the dissolved gas as amount of substance of the
394 // mixture component C related to the total volume of the liquid phase.
395 auto const cCL = H * mass_mole_fractions_data.xnCG * pGR;
396 // Fortunately for the developer, the signs of the derivatives of the
397 // composition of binary mixtures are often opposed.
398 auto const dxnCG_dpGR = -dxnWG_dpGR;
399 auto const dxnCG_dT = -dxnWG_dT;
400
401 auto const dcCL_dpGR =
402 (dH_dpGR * mass_mole_fractions_data.xnCG + H * dxnCG_dpGR) * pGR +
403 H * mass_mole_fractions_data.xnCG;
404 auto const dcCL_dT =
405 pGR * (dH_dT * mass_mole_fractions_data.xnCG + H * dxnCG_dT);
406
407 variables.concentration = cCL;
408 // Liquid density including dissolved gas components. Attention! This
409 // only works if the concentration of the C-component is taken into
410 // account in the selected equation of state, e.g. via a (multi)-linear
411 // equation of state. Should a constant density be assumed, no
412 // dissolution will take place, since the composition of the water phase
413 // is determined via the mass fractions (as the ratio of the densities
414 // of solvent and solution). NB! This problem did not occur with the gas
415 // phase because the composition there was determined via the molar
416 // fractions (ratio of the partial pressures).
417 fluid_density_data.rho_LR =
418 liquid_phase.property(MaterialPropertyLib::PropertyType::density)
419 .template value<double>(variables, x_t.x, x_t.t, x_t.dt);
420 variables.density = fluid_density_data.rho_LR;
421
422 // Gas component partial density in liquid phase
423 constituent_density_data.rho_C_LR = fluid_density_data.rho_LR - rho_W_LR();
424
425 // liquid phase composition (mass fraction)
426 mass_mole_fractions_data.xmWL =
427 std::clamp(rho_W_LR() / fluid_density_data.rho_LR, 0., 1.);
428 auto const xmCL = 1. - mass_mole_fractions_data.xmWL;
429
430 // Attention! Usually a multi-linear equation of state is used to
431 // determine the density of the solution. This requires independent
432 // variables, but in this case the concentration is not independent, but
433 // is determined via the equilibrium state. The exact derivation of the
434 // density according to e.g. the pressure pLR is thus:
435 //
436 // drho_d_pGR = rho_ref * (beta_pLR + betaC * dC_dpLR)
437 //
438 // instead of
439 //
440 // d_rho_d_pGR =
441 // liquid_phase.property(MaterialPropertyLib::PropertyType::density)
442 // .template dValue<double>(
443 // variables,
444 // MaterialPropertyLib::Variable::liquid_phase_pressure,
445 // x_t.x, x_t.t, x_t.dt);
446
447 auto const rho_ref_betaP =
448 liquid_phase.property(MaterialPropertyLib::PropertyType::density)
449 .template dValue<double>(
451 x_t.x, x_t.t, x_t.dt);
452
453 auto const rho_ref_betaT =
454 liquid_phase.property(MaterialPropertyLib::PropertyType::density)
455 .template dValue<double>(variables,
457 x_t.x, x_t.t, x_t.dt);
458
459 auto const rho_ref_betaC =
460 liquid_phase.property(MaterialPropertyLib::PropertyType::density)
461 .template dValue<double>(
463 x_t.t, x_t.dt);
464
465 // liquid phase density derivatives
466 auto const drhoLR_dpGR = rho_ref_betaP + rho_ref_betaC * dcCL_dpGR;
467 auto const drhoLR_dpCap = -rho_ref_betaP;
468 auto const drhoLR_dT = rho_ref_betaT + rho_ref_betaC * dcCL_dT;
469
470 // solvent partial density derivatives
471 auto const drhoWLR_dpGR = rho_ref_betaP;
472 auto const drhoWLR_dpCap = -rho_ref_betaP;
473 auto const drhoWLR_dT = rho_ref_betaT;
474
475 // liquid phase mass fraction derivatives
476 cv.dxmWL_dpGR =
477 1. / fluid_density_data.rho_LR *
478 (drhoWLR_dpGR - mass_mole_fractions_data.xmWL * drhoLR_dpGR);
479 cv.dxmWL_dpCap =
480 1. / fluid_density_data.rho_LR *
481 (drhoWLR_dpCap - mass_mole_fractions_data.xmWL * drhoLR_dpCap);
482 cv.dxmWL_dT = 1. / fluid_density_data.rho_LR *
483 (drhoWLR_dT - mass_mole_fractions_data.xmWL * drhoLR_dT);
484
485 // liquid phase molar fractions and derivatives
486 mass_mole_fractions_data.xnWL =
487 mass_mole_fractions_data.xmWL * M_C /
488 (mass_mole_fractions_data.xmWL * M_C + xmCL * M_W);
489
490 // Reference to the pure liquid component
491 auto const& solvent_component =
492 liquid_phase.component(liquid_phase_solvent_component_index_);
493
494 // specific heat capacities of liquid phase components
495 auto const cpCL =
496 solute_component
498 .template value<double>(variables, x_t.x, x_t.t, x_t.dt);
499 auto const cpWL =
500 solvent_component
502 .template value<double>(variables, x_t.x, x_t.t, x_t.dt);
503
504 // specific heat of solution
505 const auto dh_sol =
506 solute_component
508 .template value<double>(variables, x_t.x, x_t.t, x_t.dt);
509
510 // specific enthalpy of liquid phase and its components
511 cv.hCL = cpCL * T + dh_sol;
512 cv.hWL = cpWL * T;
513 enthalpy_data.h_L = xmCL * cv.hCL + mass_mole_fractions_data.xmWL * cv.hWL;
514
515 // specific inner energies of liquid phase
516 cv.uL = enthalpy_data.h_L;
517
518 // diffusion
519 auto const D_C_L_m =
520 solute_component.property(MaterialPropertyLib::PropertyType::diffusion)
521 .template value<double>(variables, x_t.x, x_t.t, x_t.dt);
523 tortuosity * D_C_L_m; // Note here that D_C_L = D_W_L.
524
525 // liquid phase viscosity
526 viscosity_data.mu_LR =
528 .template value<double>(variables, x_t.x, x_t.t, x_t.dt);
529}
530
531} // namespace ConstitutiveRelations
532} // namespace ProcessLib::TH2M
#define OGS_FATAL(...)
Definition Error.h:26
void DBUG(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:30
Property const & property(PropertyType const &) const
A get-function for retrieving a certain property.
Definition Component.cpp:33
Property const & property(PropertyType const &p) const
Definition Medium.cpp:54
Component const & component(std::size_t const &index) const
Definition Phase.cpp:33
static const std::array< std::string, PropertyType::number_of_properties > property_enum_to_string
int findComponentIndex(std::map< int, std::shared_ptr< MaterialPropertyLib::Medium > > const &media, std::string const &phase_name, MaterialPropertyLib::PropertyType property_type)
int numberOfComponents(std::map< int, std::shared_ptr< MaterialPropertyLib::Medium > > const &media, std::string const &phase_name)
ParameterLib::SpatialPosition x
Definition Base.h:74
MaterialPropertyLib::Medium const & medium
Definition Base.h:42
MaterialPropertyLib::Phase const & liquid
Definition Base.h:44
MaterialPropertyLib::Phase const & gas
Definition Base.h:45
void eval(SpaceTimeData const &x_t, MediaData const &media_data, GasPressureData const &p_GR, CapillaryPressureData const &p_cap, TemperatureData const &T_data, PureLiquidDensityData const &rho_W_LR, ViscosityData &viscosity_data, EnthalpyData &enthalpy_data, MassMoleFractionsData &mass_mole_fractions_data, FluidDensityData &fluid_density_data, VapourPartialPressureData &vapour_pressure_data, ConstituentDensityData &constituent_density_data, PhaseTransitionData &cv) const override
PhaseTransition(std::map< int, std::shared_ptr< MaterialPropertyLib::Medium > > const &media)