https://mooseframework.inl.gov
Loading...
Searching...
No Matches
PorousFlowBrineCO2.C
Go to the documentation of this file.
1//* This file is part of the MOOSE framework
2//* https://mooseframework.inl.gov
3//*
4//* All rights reserved, see COPYRIGHT for full restrictions
5//* https://github.com/idaholab/moose/blob/master/COPYRIGHT
6//*
7//* Licensed under LGPL 2.1, please see LICENSE for details
8//* https://www.gnu.org/licenses/lgpl-2.1.html
9
10#include "PorousFlowBrineCO2.h"
13#include "MathUtils.h"
14#include "Conversion.h"
15
17
20{
22 params.addRequiredParam<UserObjectName>("brine_fp", "The name of the user object for brine");
23 params.addRequiredParam<UserObjectName>("co2_fp", "The name of the user object for CO2");
24 params.addParam<unsigned int>("salt_component", 2, "The component number of salt");
25 params.addClassDescription("Fluid state class for brine and CO2");
26 return params;
27}
28
31 _salt_component(getParam<unsigned int>("salt_component")),
32 _brine_fp(getUserObject<BrineFluidProperties>("brine_fp")),
33 _co2_fp(getUserObject<SinglePhaseFluidProperties>("co2_fp")),
34 _Mh2o(_brine_fp.molarMassH2O()),
35 _invMh2o(1.0 / _Mh2o),
36 _Mco2(_co2_fp.molarMass()),
37 _Mnacl(_brine_fp.molarMassNaCl()),
38 _Rbar(_R * 10.0),
39 _Tlower(372.15),
40 _Tupper(382.15),
41 _Zmin(1.0e-4),
42 _co2_henry(_co2_fp.henryCoefficients())
43{
44 // Check that the correct FluidProperties UserObjects have been provided
45 if (_co2_fp.fluidName() != "co2")
46 paramError("co2_fp", "A valid CO2 FluidProperties UserObject must be provided");
47
48 if (_brine_fp.fluidName() != "brine")
49 paramError("brine_fp", "A valid Brine FluidProperties UserObject must be provided");
50
51 // Set the number of phases and components, and their indexes
52 _num_phases = 2;
56
57 // Check that _aqueous_phase_number is <= total number of phases
59 paramError("liquid_phase_number",
60 "This value is larger than the possible number of phases ",
62
63 // Check that _aqueous_fluid_component is <= total number of fluid components
65 paramError("liquid_fluid_component",
66 "This value is larger than the possible number of fluid components",
68
69 // Check that the salt component index is not identical to the liquid fluid component
72 "salt_component",
73 "The value provided must be different from the value entered in liquid_fluid_component");
74
75 // Check that _salt_component is <= total number of fluid components
77 paramError("salt_component",
78 "The value provided is larger than the possible number of fluid components",
80
82}
83
84std::string
86{
87 return "brine-co2";
88}
89
90void
92 Real temperature,
93 Real Xnacl,
94 Real Z,
95 unsigned int qp,
96 std::vector<FluidStateProperties> & fsp) const
97{
98 // Make AD versions of primary variables then call AD thermophysicalProperties()
99 ADReal p = pressure;
100 Moose::derivInsert(p.derivatives(), _pidx, 1.0);
101 ADReal T = temperature;
102 Moose::derivInsert(T.derivatives(), _Tidx, 1.0);
103 ADReal Zco2 = Z;
104 Moose::derivInsert(Zco2.derivatives(), _Zidx, 1.0);
105 ADReal X = Xnacl;
106 Moose::derivInsert(X.derivatives(), _Xidx, 1.0);
107
108 thermophysicalProperties(p, T, X, Zco2, qp, fsp);
109}
110
111void
113 const ADReal & temperature,
114 const ADReal & Xnacl,
115 const ADReal & Z,
116 unsigned int qp,
117 std::vector<FluidStateProperties> & fsp) const
118{
121
122 // Check whether the input temperature is within the region of validity
123 checkVariables(pressure.value(), temperature.value());
124
125 // Clear all of the FluidStateProperties data
127
128 FluidStatePhaseEnum phase_state;
129 massFractions(pressure, temperature, Xnacl, Z, phase_state, fsp);
130
131 switch (phase_state)
132 {
134 {
135 // Set the gas saturations
136 gas.saturation = 1.0;
137
138 // Calculate gas properties
139 gasProperties(pressure, temperature, fsp);
140
141 break;
142 }
143
145 {
146 // Calculate the liquid properties
147 const ADReal liquid_pressure = pressure - _pc.capillaryPressure(1.0, qp);
148 liquidProperties(liquid_pressure, temperature, Xnacl, fsp);
149
150 break;
151 }
152
154 {
155 // Calculate the gas and liquid properties in the two phase region
156 twoPhaseProperties(pressure, temperature, Xnacl, Z, qp, fsp);
157
158 break;
159 }
160 }
161
162 // Liquid saturations can now be set
163 liquid.saturation = 1.0 - gas.saturation;
164
165 // Save pressures to FluidStateProperties object
166 gas.pressure = pressure;
167 liquid.pressure = pressure - _pc.capillaryPressure(liquid.saturation, qp);
168}
169
170void
172 const ADReal & temperature,
173 const ADReal & Xnacl,
174 const ADReal & Z,
175 FluidStatePhaseEnum & phase_state,
176 std::vector<FluidStateProperties> & fsp) const
177{
180
181 ADReal Xco2 = 0.0;
182 ADReal Yh2o = 0.0;
183 ADReal Yco2 = 0.0;
184
185 // If the amount of CO2 is less than the smallest solubility, then all CO2 will
186 // be dissolved, and the equilibrium mass fractions do not need to be computed
187 if (Z.value() < _Zmin)
188 phase_state = FluidStatePhaseEnum::LIQUID;
189
190 else
191 {
192 // Equilibrium mass fraction of CO2 in liquid and H2O in gas phases
193 equilibriumMassFractions(pressure, temperature, Xnacl, Xco2, Yh2o);
194
195 Yco2 = 1.0 - Yh2o;
196
197 // Determine which phases are present based on the value of z
198 phaseState(Z.value(), Xco2.value(), Yco2.value(), phase_state);
199 }
200
201 // The equilibrium mass fractions calculated above are only correct in the two phase
202 // state. If only liquid or gas phases are present, the mass fractions are given by
203 // the total mass fraction z
204 ADReal Xh2o = 0.0;
205
206 switch (phase_state)
207 {
209 {
210 Xco2 = Z;
211 Yco2 = 0.0;
212 Xh2o = 1.0 - Z;
213 Yh2o = 0.0;
214 break;
215 }
216
218 {
219 Xco2 = 0.0;
220 Yco2 = Z;
221 Yh2o = 1.0 - Z;
222 break;
223 }
224
226 {
227 // Keep equilibrium mass fractions
228 Xh2o = 1.0 - Xco2;
229 break;
230 }
231 }
232
233 // Save the mass fractions in the FluidStateProperties object
235 liquid.mass_fraction[_gas_fluid_component] = Xco2;
236 liquid.mass_fraction[_salt_component] = Xnacl;
239}
240
241void
243 const ADReal & temperature,
244 std::vector<FluidStateProperties> & fsp) const
245{
247
248 // Gas density, viscosity and enthalpy are approximated with pure CO2 - no correction due
249 // to the small amount of water vapor is made
250 ADReal co2_density, co2_viscosity;
251 _co2_fp.rho_mu_from_p_T(pressure, temperature, co2_density, co2_viscosity);
252
253 ADReal co2_enthalpy = _co2_fp.h_from_p_T(pressure, temperature);
254
255 // Save the values to the FluidStateProperties object. Note that derivatives wrt z are 0
256 gas.density = co2_density;
257 gas.viscosity = co2_viscosity;
258 gas.enthalpy = co2_enthalpy;
259
260 mooseAssert(gas.density.value() > 0.0, "Gas density must be greater than zero");
261 gas.internal_energy = gas.enthalpy - pressure / gas.density;
262}
263
264void
266 const ADReal & temperature,
267 const ADReal & Xnacl,
268 std::vector<FluidStateProperties> & fsp) const
269{
271
272 // The liquid density includes the density increase due to dissolved CO2
273 const ADReal brine_density = _brine_fp.rho_from_p_T_X(pressure, temperature, Xnacl);
274
275 // Mass fraction of CO2 in liquid phase
276 const ADReal Xco2 = liquid.mass_fraction[_gas_fluid_component];
277
278 // The liquid density
279 const ADReal co2_partial_density = partialDensityCO2(temperature);
280
281 const ADReal liquid_density = 1.0 / (Xco2 / co2_partial_density + (1.0 - Xco2) / brine_density);
282
283 // Assume that liquid viscosity is just the brine viscosity
284 const ADReal liquid_viscosity = _brine_fp.mu_from_p_T_X(pressure, temperature, Xnacl);
285
286 // Liquid enthalpy (including contribution due to the enthalpy of dissolution)
287 const ADReal brine_enthalpy = _brine_fp.h_from_p_T_X(pressure, temperature, Xnacl);
288
289 // Enthalpy of CO2
290 const ADReal co2_enthalpy = _co2_fp.h_from_p_T(pressure, temperature);
291
292 // Enthalpy of dissolution
293 const ADReal hdis = enthalpyOfDissolution(temperature);
294
295 const ADReal liquid_enthalpy = (1.0 - Xco2) * brine_enthalpy + Xco2 * (co2_enthalpy + hdis);
296
297 // Save the values to the FluidStateProperties object
298 liquid.density = liquid_density;
299 liquid.viscosity = liquid_viscosity;
300 liquid.enthalpy = liquid_enthalpy;
301
302 mooseAssert(liquid.density.value() > 0.0, "Liquid density must be greater than zero");
303 liquid.internal_energy = liquid.enthalpy - pressure / liquid.density;
304}
305
306ADReal
308 const ADReal & temperature,
309 const ADReal & Xnacl,
310 const ADReal & Z,
311 std::vector<FluidStateProperties> & fsp) const
312{
313 auto & gas = fsp[_gas_phase_number];
314 auto & liquid = fsp[_aqueous_phase_number];
315
316 // Approximate liquid density as saturation isn't known yet, by using the gas
317 // pressure rather than the liquid pressure. This does result in a small error
318 // in the calculated saturation, but this is below the error associated with
319 // the correlations. A more accurate saturation could be found iteraviely,
320 // at the cost of increased computational expense
321
322 // Gas density
323 const ADReal gas_density = _co2_fp.rho_from_p_T(pressure, temperature);
324
325 // Approximate liquid density as saturation isn't known yet
326 const ADReal brine_density = _brine_fp.rho_from_p_T_X(pressure, temperature, Xnacl);
327
328 // Mass fraction of CO2 in liquid phase
329 const ADReal Xco2 = liquid.mass_fraction[_gas_fluid_component];
330
331 // The liquid density
332 const ADReal co2_partial_density = partialDensityCO2(temperature);
333
334 const ADReal liquid_density = 1.0 / (Xco2 / co2_partial_density + (1.0 - Xco2) / brine_density);
335
336 const ADReal Yco2 = gas.mass_fraction[_gas_fluid_component];
337
338 // Set mass equilibrium constants used in the calculation of vapor mass fraction
339 const ADReal K0 = Yco2 / Xco2;
340 const ADReal K1 = (1.0 - Yco2) / (1.0 - Xco2);
341 const ADReal vapor_mass_fraction = vaporMassFraction(Z, K0, K1);
342
343 // The gas saturation in the two phase case
344 const ADReal saturation = vapor_mass_fraction * liquid_density /
345 (gas_density + vapor_mass_fraction * (liquid_density - gas_density));
346
347 return saturation;
348}
349
350void
352 const ADReal & temperature,
353 const ADReal & Xnacl,
354 const ADReal & Z,
355 unsigned int qp,
356 std::vector<FluidStateProperties> & fsp) const
357{
358 auto & gas = fsp[_gas_phase_number];
359
360 // Calculate all of the gas phase properties, as these don't depend on saturation
361 gasProperties(pressure, temperature, fsp);
362
363 // The gas saturation in the two phase case
364 gas.saturation = saturation(pressure, temperature, Xnacl, Z, fsp);
365
366 // The liquid pressure and properties can now be calculated
367 const ADReal liquid_pressure = pressure - _pc.capillaryPressure(1.0 - gas.saturation, qp);
368 liquidProperties(liquid_pressure, temperature, Xnacl, fsp);
369}
370
371void
373 const ADReal & temperature,
374 const ADReal & Xnacl,
375 ADReal & Xco2,
376 ADReal & Yh2o) const
377{
378 // Mole fractions at equilibrium
379 ADReal xco2, yh2o;
380 equilibriumMoleFractions(pressure, temperature, Xnacl, xco2, yh2o);
381
382 // The mass fraction of H2O in gas (assume no salt in gas phase) and derivatives
383 // wrt p, T, and X
384 Yh2o = yh2o * _Mh2o / (yh2o * _Mh2o + (1.0 - yh2o) * _Mco2);
385
386 // NaCl molality (mol/kg)
387 const ADReal mnacl = Xnacl / (1.0 - Xnacl) / _Mnacl;
388
389 // The molality of CO2 in 1kg of H2O
390 const ADReal mco2 = xco2 * (2.0 * mnacl + _invMh2o) / (1.0 - xco2);
391 // The mass fraction of CO2 in brine is then
392 const ADReal denominator = (1.0 + mnacl * _Mnacl + mco2 * _Mco2);
393 Xco2 = mco2 * _Mco2 / denominator;
394}
395
396void
398 const ADReal & temperature,
399 const ADReal & co2_density,
400 ADReal & fco2,
401 ADReal & fh2o) const
402{
403 using std::log, std::exp, std::pow;
404
405 if (temperature.value() > 373.15)
407 ": fugacityCoefficientsLowTemp() is not valid for T > 373.15K. Use "
408 "fugacityCoefficientsHighTemp() instead");
409
410 // Need pressure in bar
411 const ADReal pbar = pressure * 1.0e-5;
412
413 // Molar volume in cm^3/mol
414 const ADReal V = _Mco2 / co2_density * 1.0e6;
415
416 // Redlich-Kwong parameters
417 const ADReal aCO2 = 7.54e7 - 4.13e4 * temperature;
418 const Real bCO2 = 27.8;
419 const Real aCO2H2O = 7.89e7;
420 const Real bH2O = 18.18;
421
422 const ADReal t15 = pow(temperature, 1.5);
423
424 // The fugacity coefficients for H2O and CO2
425 auto lnPhi = [V, aCO2, bCO2, t15, this](ADReal a, ADReal b)
426 {
427 return log(V / (V - bCO2)) + b / (V - bCO2) -
428 2.0 * a / (_Rbar * t15 * bCO2) * log((V + bCO2) / V) +
429 aCO2 * b / (_Rbar * t15 * bCO2 * bCO2) * (log((V + bCO2) / V) - bCO2 / (V + bCO2));
430 };
431
432 const ADReal lnPhiH2O = lnPhi(aCO2H2O, bH2O) - log(pbar * V / (_Rbar * temperature));
433 const ADReal lnPhiCO2 = lnPhi(aCO2, bCO2) - log(pbar * V / (_Rbar * temperature));
434
435 fh2o = exp(lnPhiH2O);
436 fco2 = exp(lnPhiCO2);
437}
438
439void
441 const ADReal & temperature,
442 const ADReal & co2_density,
443 const ADReal & xco2,
444 const ADReal & yh2o,
445 ADReal & fco2,
446 ADReal & fh2o) const
447{
448 if (temperature.value() <= 373.15)
450 ": fugacityCoefficientsHighTemp() is not valid for T <= 373.15K. Use "
451 "fugacityCoefficientsLowTemp() instead");
452
453 fh2o = fugacityCoefficientH2OHighTemp(pressure, temperature, co2_density, xco2, yh2o);
454 fco2 = fugacityCoefficientCO2HighTemp(pressure, temperature, co2_density, xco2, yh2o);
455}
456
457ADReal
459 const ADReal & temperature,
460 const ADReal & co2_density,
461 const ADReal & xco2,
462 const ADReal & yh2o) const
463{
464 using std::sqrt, std::pow, std::log, std::exp;
465
466 // Need pressure in bar
467 const ADReal pbar = pressure * 1.0e-5;
468 // Molar volume in cm^3/mol
469 const ADReal V = _Mco2 / co2_density * 1.0e6;
470
471 // Redlich-Kwong parameters
472 const ADReal yco2 = 1.0 - yh2o;
473 const ADReal xh2o = 1.0 - xco2;
474
475 const ADReal aCO2 = 8.008e7 - 4.984e4 * temperature;
476 const ADReal aH2O = 1.337e8 - 1.4e4 * temperature;
477 const Real bCO2 = 28.25;
478 const Real bH2O = 15.7;
479 const ADReal KH2OCO2 = 1.427e-2 - 4.037e-4 * temperature;
480 const ADReal KCO2H2O = 0.4228 - 7.422e-4 * temperature;
481 const ADReal kH2OCO2 = KH2OCO2 * yh2o + KCO2H2O * yco2;
482 const ADReal kCO2H2O = KCO2H2O * yh2o + KH2OCO2 * yco2;
483
484 const ADReal aH2OCO2 = sqrt(aCO2 * aH2O) * (1.0 - kH2OCO2);
485 const ADReal aCO2H2O = sqrt(aCO2 * aH2O) * (1.0 - kCO2H2O);
486
487 const ADReal amix = yh2o * yh2o * aH2O + yh2o * yco2 * (aH2OCO2 + aCO2H2O) + yco2 * yco2 * aCO2;
488 const ADReal bmix = yh2o * bH2O + yco2 * bCO2;
489
490 const ADReal t15 = pow(temperature, 1.5);
491
492 ADReal lnPhiH2O = bH2O / bmix * (pbar * V / (_Rbar * temperature) - 1.0) -
493 log(pbar * (V - bmix) / (_Rbar * temperature));
494 ADReal term3 = (2.0 * yh2o * aH2O + yco2 * (aH2OCO2 + aCO2H2O) -
495 yh2o * yco2 * sqrt(aH2O * aCO2) * (kH2OCO2 - kCO2H2O) * (yh2o - yco2) +
496 xh2o * xco2 * sqrt(aH2O * aCO2) * (kH2OCO2 - kCO2H2O)) /
497 amix;
498 term3 -= bH2O / bmix;
499 term3 *= amix / (bmix * _Rbar * t15) * log(V / (V + bmix));
500 lnPhiH2O += term3;
501
502 return exp(lnPhiH2O);
503}
504
505ADReal
507 const ADReal & temperature,
508 const ADReal & co2_density,
509 const ADReal & xco2,
510 const ADReal & yh2o) const
511{
512 using std::sqrt, std::pow, std::log, std::exp;
513
514 // Need pressure in bar
515 const ADReal pbar = pressure * 1.0e-5;
516 // Molar volume in cm^3/mol
517 const ADReal V = _Mco2 / co2_density * 1.0e6;
518
519 // Redlich-Kwong parameters
520 const ADReal yco2 = 1.0 - yh2o;
521 const ADReal xh2o = 1.0 - xco2;
522
523 const ADReal aCO2 = 8.008e7 - 4.984e4 * temperature;
524 const ADReal aH2O = 1.337e8 - 1.4e4 * temperature;
525 const Real bCO2 = 28.25;
526 const Real bH2O = 15.7;
527 const ADReal KH2OCO2 = 1.427e-2 - 4.037e-4 * temperature;
528 const ADReal KCO2H2O = 0.4228 - 7.422e-4 * temperature;
529 const ADReal kH2OCO2 = KH2OCO2 * yh2o + KCO2H2O * yco2;
530 const ADReal kCO2H2O = KCO2H2O * yh2o + KH2OCO2 * yco2;
531
532 const ADReal aH2OCO2 = sqrt(aCO2 * aH2O) * (1.0 - kH2OCO2);
533 const ADReal aCO2H2O = sqrt(aCO2 * aH2O) * (1.0 - kCO2H2O);
534
535 const ADReal amix = yh2o * yh2o * aH2O + yh2o * yco2 * (aH2OCO2 + aCO2H2O) + yco2 * yco2 * aCO2;
536 const ADReal bmix = yh2o * bH2O + yco2 * bCO2;
537
538 const ADReal t15 = pow(temperature, 1.5);
539
540 ADReal lnPhiCO2 = bCO2 / bmix * (pbar * V / (_Rbar * temperature) - 1.0) -
541 log(pbar * (V - bmix) / (_Rbar * temperature));
542
543 ADReal term3 = (2.0 * yco2 * aCO2 + yh2o * (aH2OCO2 + aCO2H2O) -
544 yh2o * yco2 * sqrt(aH2O * aCO2) * (kH2OCO2 - kCO2H2O) * (yh2o - yco2) +
545 xh2o * xco2 * sqrt(aH2O * aCO2) * (kCO2H2O - kH2OCO2)) /
546 amix;
547
548 lnPhiCO2 += (term3 - bCO2 / bmix) * amix / (bmix * _Rbar * t15) * log(V / (V + bmix));
549
550 return exp(lnPhiCO2);
551}
552
553ADReal
554PorousFlowBrineCO2::activityCoefficientH2O(const ADReal & temperature, const ADReal & xco2) const
555{
556 using std::exp;
557
558 if (temperature.value() <= 373.15)
559 return 1.0;
560 else
561 {
562 const ADReal Tref = temperature - 373.15;
563 const ADReal xh2o = 1.0 - xco2;
564 const ADReal Am = -3.084e-2 * Tref + 1.927e-5 * Tref * Tref;
565
566 return exp((Am - 2.0 * Am * xh2o) * xco2 * xco2);
567 }
568}
569
570ADReal
571PorousFlowBrineCO2::activityCoefficientCO2(const ADReal & temperature, const ADReal & xco2) const
572{
573 using std::exp;
574
575 if (temperature.value() <= 373.15)
576 return 1.0;
577 else
578 {
579 const ADReal Tref = temperature - 373.15;
580 const ADReal xh2o = 1.0 - xco2;
581 const ADReal Am = -3.084e-2 * Tref + 1.927e-5 * Tref * Tref;
582
583 return exp(2.0 * Am * xco2 * xh2o * xh2o);
584 }
585}
586
587ADReal
589 const ADReal & temperature,
590 const ADReal & Xnacl) const
591{
592 using std::log, std::exp;
593
594 // Need pressure in bar
595 const ADReal pbar = pressure * 1.0e-5;
596 // Need NaCl molality (mol/kg)
597 const ADReal mnacl = Xnacl / (1.0 - Xnacl) / _Mnacl;
598
599 const ADReal lambda = -0.411370585 + 6.07632013e-4 * temperature + 97.5347708 / temperature -
600 0.0237622469 * pbar / temperature +
601 0.0170656236 * pbar / (630.0 - temperature) +
602 1.41335834e-5 * temperature * log(pbar);
603
604 const ADReal xi = 3.36389723e-4 - 1.9829898e-5 * temperature +
605 2.12220830e-3 * pbar / temperature -
606 5.24873303e-3 * pbar / (630.0 - temperature);
607
608 return exp(2.0 * lambda * mnacl + xi * mnacl * mnacl);
609}
610
611ADReal
613 const ADReal & Xnacl) const
614{
615 using std::exp;
616
617 // Need NaCl molality (mol/kg)
618 const ADReal mnacl = Xnacl / (1.0 - Xnacl) / _Mnacl;
619
620 const ADReal T2 = temperature * temperature;
621 const ADReal T3 = temperature * T2;
622
623 const ADReal lambda = 2.217e-4 * temperature + 1.074 / temperature + 2648.0 / T2;
624 const ADReal xi = 1.3e-5 * temperature - 20.12 / temperature + 5259.0 / T2;
625
626 return (1.0 - mnacl / _invMh2o) * exp(2.0 * lambda * mnacl + xi * mnacl * mnacl);
627}
628
629ADReal
631{
632 using std::pow;
633
634 // Uses temperature in Celsius
635 const ADReal Tc = temperature - _T_c2k;
636 const ADReal Tc2 = Tc * Tc;
637 const ADReal Tc3 = Tc2 * Tc;
638 const ADReal Tc4 = Tc3 * Tc;
639
640 ADReal logK0H2O;
641
642 if (Tc <= 99.0)
643 logK0H2O = -2.209 + 3.097e-2 * Tc - 1.098e-4 * Tc2 + 2.048e-7 * Tc3;
644
645 else if (Tc > 99.0 && Tc < 109.0)
646 {
647 const ADReal Tint = (Tc - 99.0) / 10.0;
648 const ADReal Tint2 = Tint * Tint;
649 logK0H2O = -0.0204026 + 0.0152513 * Tint + 0.417565 * Tint2 - 0.278636 * Tint * Tint2;
650 }
651
652 else // 109 <= Tc <= 300
653 logK0H2O = -2.1077 + 2.8127e-2 * Tc - 8.4298e-5 * Tc2 + 1.4969e-7 * Tc3 - 1.1812e-10 * Tc4;
654
655 return pow(10.0, logK0H2O);
656}
657
658ADReal
660{
661 using std::pow;
662
663 // Uses temperature in Celsius
664 const ADReal Tc = temperature - _T_c2k;
665 const ADReal Tc2 = Tc * Tc;
666 const ADReal Tc3 = Tc2 * Tc;
667
668 ADReal logK0CO2;
669
670 if (Tc <= 99.0)
671 logK0CO2 = 1.189 + 1.304e-2 * Tc - 5.446e-5 * Tc2;
672
673 else if (Tc > 99.0 && Tc < 109.0)
674 {
675 const ADReal Tint = (Tc - 99.0) / 10.0;
676 const ADReal Tint2 = Tint * Tint;
677 logK0CO2 = 1.9462 + 2.25692e-2 * Tint - 9.49577e-3 * Tint2 - 6.77721e-3 * Tint * Tint2;
678 }
679
680 else // 109 <= Tc <= 300
681 logK0CO2 = 1.668 + 3.992e-3 * Tc - 1.156e-5 * Tc2 + 1.593e-9 * Tc3;
682
683 return pow(10.0, logK0CO2);
684}
685
686void
688 const ADReal & temperature,
689 const ADReal & Xnacl,
690 ADReal & xco2,
691 ADReal & yh2o) const
692{
693 if (temperature.value() <= _Tlower)
694 {
695 equilibriumMoleFractionsLowTemp(pressure, temperature, Xnacl, xco2, yh2o);
696 }
697 else if (temperature.value() > _Tlower && temperature.value() < _Tupper)
698 {
699 // Cubic polynomial in this regime
700 const Real Tint = (temperature.value() - _Tlower) / 10.0;
701
702 // Equilibrium mole fractions and derivatives at the lower temperature
703 ADReal Tlower = _Tlower;
704 Moose::derivInsert(Tlower.derivatives(), _Tidx, 1.0);
705
706 ADReal xco2_lower, yh2o_lower;
707 equilibriumMoleFractionsLowTemp(pressure, Tlower, Xnacl, xco2_lower, yh2o_lower);
708
709 const Real dxco2_dT_lower = xco2_lower.derivatives()[_Tidx];
710 const Real dyh2o_dT_lower = yh2o_lower.derivatives()[_Tidx];
711
712 // Equilibrium mole fractions and derivatives at the upper temperature
713 Real xco2_upper, yh2o_upper;
714 Real co2_density_upper = _co2_fp.rho_from_p_T(pressure.value(), _Tupper);
715
717 pressure.value(), _Tupper, Xnacl.value(), co2_density_upper, xco2_upper, yh2o_upper);
718
719 Real A, dA_dp, dA_dT, B, dB_dp, dB_dT, dB_dX;
720 funcABHighTemp(pressure.value(),
721 _Tupper,
722 Xnacl.value(),
723 co2_density_upper,
724 xco2_upper,
725 yh2o_upper,
726 A,
727 dA_dp,
728 dA_dT,
729 B,
730 dB_dp,
731 dB_dT,
732 dB_dX);
733
734 const Real dyh2o_dT_upper =
735 ((1.0 - B) * dA_dT + (A - 1.0) * A * dB_dT) / (1.0 - A * B) / (1.0 - A * B);
736 const Real dxco2_dT_upper = dB_dT * (1.0 - yh2o_upper) - B * dyh2o_dT_upper;
737
738 // The mole fractions in this regime are then found by interpolation
739 Real xco2r, yh2or, dxco2_dT, dyh2o_dT;
741 Tint, xco2_lower.value(), dxco2_dT_lower, xco2_upper, dxco2_dT_upper, xco2r, dxco2_dT);
743 Tint, yh2o_lower.value(), dyh2o_dT_lower, yh2o_upper, dyh2o_dT_upper, yh2or, dyh2o_dT);
744
745 xco2 = xco2r;
746 Moose::derivInsert(xco2.derivatives(), _pidx, xco2_lower.derivatives()[_pidx]);
747 Moose::derivInsert(xco2.derivatives(), _Tidx, dxco2_dT);
748 Moose::derivInsert(xco2.derivatives(), _Xidx, xco2_lower.derivatives()[_Xidx]);
749
750 yh2o = yh2or;
751 Moose::derivInsert(yh2o.derivatives(), _pidx, yh2o_lower.derivatives()[_pidx]);
752 Moose::derivInsert(yh2o.derivatives(), _Tidx, dyh2o_dT);
753 Moose::derivInsert(yh2o.derivatives(), _Xidx, yh2o_lower.derivatives()[_Xidx]);
754 }
755 else
756 {
757 // CO2 density and derivatives wrt pressure and temperature
758 const Real co2_density = _co2_fp.rho_from_p_T(pressure.value(), temperature.value());
759
760 // Equilibrium mole fractions solved using iteration in this regime
761 Real xco2r, yh2or;
763 pressure.value(), temperature.value(), Xnacl.value(), co2_density, xco2r, yh2or);
764
765 // Can use these in funcABHighTemp() to get derivatives analytically rather than by iteration
766 Real A, dA_dp, dA_dT, B, dB_dp, dB_dT, dB_dX;
767 funcABHighTemp(pressure.value(),
768 temperature.value(),
769 Xnacl.value(),
770 co2_density,
771 xco2r,
772 yh2or,
773 A,
774 dA_dp,
775 dA_dT,
776 B,
777 dB_dp,
778 dB_dT,
779 dB_dX);
780
781 const Real dyh2o_dp =
782 ((1.0 - B) * dA_dp + (A - 1.0) * A * dB_dp) / (1.0 - A * B) / (1.0 - A * B);
783 const Real dxco2_dp = dB_dp * (1.0 - yh2or) - B * dyh2o_dp;
784
785 const Real dyh2o_dT =
786 ((1.0 - B) * dA_dT + (A - 1.0) * A * dB_dT) / (1.0 - A * B) / (1.0 - A * B);
787 const Real dxco2_dT = dB_dT * (1.0 - yh2or) - B * dyh2o_dT;
788
789 const Real dyh2o_dX = ((A - 1.0) * A * dB_dX) / (1.0 - A * B) / (1.0 - A * B);
790 const Real dxco2_dX = dB_dX * (1.0 - yh2or) - B * dyh2o_dX;
791
792 xco2 = xco2r;
793 Moose::derivInsert(xco2.derivatives(), _pidx, dxco2_dp);
794 Moose::derivInsert(xco2.derivatives(), _Tidx, dxco2_dT);
795 Moose::derivInsert(xco2.derivatives(), _Xidx, dxco2_dX);
796
797 yh2o = yh2or;
798 Moose::derivInsert(yh2o.derivatives(), _pidx, dyh2o_dp);
799 Moose::derivInsert(yh2o.derivatives(), _Tidx, dyh2o_dT);
800 Moose::derivInsert(yh2o.derivatives(), _Xidx, dyh2o_dX);
801 }
802}
803
804void
806 const ADReal & temperature,
807 const ADReal & Xnacl,
808 ADReal & xco2,
809 ADReal & yh2o) const
810{
811 if (temperature.value() > 373.15)
813 ": equilibriumMoleFractionsLowTemp() is not valid for T > 373.15K. Use "
814 "equilibriumMoleFractions() instead");
815
816 // CO2 density and derivatives wrt pressure and temperature
817 const ADReal co2_density = _co2_fp.rho_from_p_T(pressure, temperature);
818
819 // Assume infinite dilution (yh20 = 0 and xco2 = 0) in low temperature regime
820 ADReal A, B;
821 funcABLowTemp(pressure, temperature, co2_density, A, B);
822
823 // As the activity coefficient for CO2 in brine used in this regime isn't a 'true'
824 // activity coefficient, we instead calculate the molality of CO2 in water, then
825 // correct it for brine, and then calculate the mole fractions.
826 // The mole fraction in pure water is
827 const ADReal yh2ow = (1.0 - B) / (1.0 / A - B);
828 const ADReal xco2w = B * (1.0 - yh2ow);
829
830 // Molality of CO2 in pure water
831 const ADReal mco2w = xco2w * _invMh2o / (1.0 - xco2w);
832 // Molality of CO2 in brine is then calculated using gamma
833 const ADReal gamma = activityCoefficient(pressure, temperature, Xnacl);
834 const ADReal mco2 = mco2w / gamma;
835
836 // Need NaCl molality (mol/kg)
837 const ADReal mnacl = Xnacl / (1.0 - Xnacl) / _Mnacl;
838
839 // Mole fractions of CO2 and H2O in liquid and gas phases
840 const ADReal total_moles = 2.0 * mnacl + _invMh2o + mco2;
841 xco2 = mco2 / total_moles;
842 yh2o = A * (1.0 - xco2 - 2.0 * mnacl / total_moles);
843}
844
845void
847 const ADReal & temperature,
848 const ADReal & co2_density,
849 ADReal & A,
850 ADReal & B) const
851{
852 using std::exp;
853
854 if (temperature.value() > 373.15)
856 ": funcABLowTemp() is not valid for T > 373.15K. Use funcABHighTemp() instead");
857
858 // Pressure in bar
859 const ADReal pbar = pressure * 1.0e-5;
860
861 // Reference pressure and partial molar volumes
862 const Real pref = 1.0;
863 const Real vCO2 = 32.6;
864 const Real vH2O = 18.1;
865
866 const ADReal delta_pbar = pbar - pref;
867 const ADReal Rt = _Rbar * temperature;
868
869 // Equilibrium constants
870 const ADReal K0H2O = equilibriumConstantH2O(temperature);
871 const ADReal K0CO2 = equilibriumConstantCO2(temperature);
872
873 // Fugacity coefficients
874 ADReal phiH2O, phiCO2;
875 fugacityCoefficientsLowTemp(pressure, temperature, co2_density, phiCO2, phiH2O);
876
877 A = K0H2O / (phiH2O * pbar) * exp(delta_pbar * vH2O / Rt);
878 B = phiCO2 * pbar / (_invMh2o * K0CO2) * exp(-delta_pbar * vCO2 / Rt);
879}
880
881void
883 Real temperature,
884 Real Xnacl,
885 Real co2_density,
886 Real xco2,
887 Real yh2o,
888 Real & A,
889 Real & B) const
890{
891 using std::exp;
892
893 if (temperature <= 373.15)
895 ": funcABHighTemp() is not valid for T <= 373.15K. Use funcABLowTemp() instead");
896
897 // Pressure in bar
898 const Real pbar = pressure * 1.0e-5;
899 // Temperature in C
900 const Real Tc = temperature - _T_c2k;
901
902 // Reference pressure and partial molar volumes
903 const Real pref = -1.9906e-1 + 2.0471e-3 * Tc + 1.0152e-4 * Tc * Tc - 1.4234e-6 * Tc * Tc * Tc +
904 1.4168e-8 * Tc * Tc * Tc * Tc;
905 const Real vCO2 = 32.6 + 3.413e-2 * (Tc - 100.0);
906 const Real vH2O = 18.1 + 3.137e-2 * (Tc - 100.0);
907
908 const Real delta_pbar = pbar - pref;
909 const Real Rt = _Rbar * temperature;
910
911 // Equilibrium constants
912 // Use dummy ADReal temperature as derivatives aren't required
913 const ADReal T = temperature;
914 Real K0H2O = equilibriumConstantH2O(T).value();
915 Real K0CO2 = equilibriumConstantCO2(T).value();
916
917 // Fugacity coefficients
918 // Use dummy ADReal variables as derivatives aren't required
919 const ADReal p = pressure;
920 const ADReal rhoco2 = co2_density;
921 const ADReal x = xco2;
922 const ADReal y = yh2o;
923
924 ADReal phiH2O, phiCO2;
925 fugacityCoefficientsHighTemp(p, T, rhoco2, x, y, phiCO2, phiH2O);
926
927 // Activity coefficients
928 const Real gammaH2O = activityCoefficientH2O(T, x).value();
929 const Real gammaCO2 = activityCoefficientCO2(T, x).value();
930
931 // Activity coefficient for CO2 in brine
932 // Use dummy ADReal Xnacl as derivatives aren't required
933 const ADReal X = Xnacl;
934 const Real gamma = activityCoefficientHighTemp(T, X).value();
935
936 A = K0H2O * gammaH2O / (phiH2O.value() * pbar) * exp(delta_pbar * vH2O / Rt);
937 B = phiCO2.value() * pbar / (_invMh2o * K0CO2 * gamma * gammaCO2) * exp(-delta_pbar * vCO2 / Rt);
938}
939
940void
942 Real temperature,
943 Real Xnacl,
944 Real co2_density,
945 Real xco2,
946 Real yh2o,
947 Real & A,
948 Real & dA_dp,
949 Real & dA_dT,
950 Real & B,
951 Real & dB_dp,
952 Real & dB_dT,
953 Real & dB_dX) const
954{
955 funcABHighTemp(pressure, temperature, Xnacl, co2_density, xco2, yh2o, A, B);
956
957 // Use finite differences for derivatives in the high temperature regime
958 const Real dp = 1.0e-2;
959 const Real dT = 1.0e-6;
960 const Real dX = 1.0e-8;
961
962 Real A2, B2;
963 funcABHighTemp(pressure + dp, temperature, Xnacl, co2_density, xco2, yh2o, A2, B2);
964 dA_dp = (A2 - A) / dp;
965 dB_dp = (B2 - B) / dp;
966
967 funcABHighTemp(pressure, temperature + dT, Xnacl, co2_density, xco2, yh2o, A2, B2);
968 dA_dT = (A2 - A) / dT;
969 dB_dT = (B2 - B) / dT;
970
971 funcABHighTemp(pressure, temperature, Xnacl + dX, co2_density, xco2, yh2o, A2, B2);
972 dB_dX = (B2 - B) / dX;
973}
974
975void
977 Real pressure, Real temperature, Real Xnacl, Real co2_density, Real & xco2, Real & yh2o) const
978{
979 // Initial guess for yh2o and xco2 (from Spycher and Pruess (2010))
980 Real y = _brine_fp.vaporPressure(temperature, 0.0) / pressure;
981 Real x = 0.009;
982
983 // Need salt mass fraction in molality
984 const Real mnacl = Xnacl / (1.0 - Xnacl) / _Mnacl;
985
986 // If y > 1, then just use y = 1, x = 0 (only a gas phase)
987 if (y >= 1.0)
988 {
989 y = 1.0;
990 x = 0.0;
991 }
992 else
993 {
994 // Residual function for Newton-Raphson
995 auto fy = [mnacl, this](Real y, Real A, Real B)
996 {
997 return y -
998 (1.0 - B) * _invMh2o / ((1.0 / A - B) * (2.0 * mnacl + _invMh2o) + 2.0 * mnacl * B);
999 };
1000
1001 // Derivative of fy wrt y
1002 auto dfy = [mnacl, this](Real A, Real B, Real dA, Real dB)
1003 {
1004 const Real denominator = (1.0 / A - B) * (2.0 * mnacl + _invMh2o) + 2.0 * mnacl * B;
1005 return 1.0 + _invMh2o * dB / denominator +
1006 (1.0 - B) * _invMh2o *
1007 (2.0 * mnacl * dB - (2.0 * mnacl + _invMh2o) * (dB + dA / A / A)) / denominator /
1008 denominator;
1009 };
1010
1011 Real A, B;
1012 Real dA, dB;
1013 const Real dy = 1.0e-8;
1014
1015 // Solve for yh2o using Newton-Raphson method
1016 unsigned int iter = 0;
1017 const Real tol = 1.0e-12;
1018 const unsigned int max_its = 10;
1019 funcABHighTemp(pressure, temperature, Xnacl, co2_density, x, y, A, B);
1020
1021 while (std::abs(fy(y, A, B)) > tol)
1022 {
1023 funcABHighTemp(pressure, temperature, Xnacl, co2_density, x, y, A, B);
1024 // Finite difference derivatives of A and B wrt y
1025 funcABHighTemp(pressure, temperature, Xnacl, co2_density, x, y + dy, dA, dB);
1026 dA = (dA - A) / dy;
1027 dB = (dB - B) / dy;
1028
1029 y = y - fy(y, A, B) / dfy(A, B, dA, dB);
1030
1031 x = B * (1.0 - y);
1032
1033 // Break if not converged and just use the value
1034 if (iter > max_its)
1035 break;
1036 }
1037 }
1038
1039 yh2o = y;
1040 xco2 = x;
1041}
1042
1043ADReal
1045{
1046 // This correlation uses temperature in C
1047 const ADReal Tc = temperature - _T_c2k;
1048 // The parial molar volume
1049 const ADReal V = 37.51 - 9.585e-2 * Tc + 8.74e-4 * Tc * Tc - 5.044e-7 * Tc * Tc * Tc;
1050
1051 return 1.0e6 * _Mco2 / V;
1052}
1053
1054Real
1056 Real pressure, Real temperature, Real Xnacl, Real saturation, unsigned int qp) const
1057{
1058 // Check whether the input pressure and temperature are within the region of validity
1059 checkVariables(pressure, temperature);
1060
1061 // As we do not require derivatives, we can simply ignore their initialisation
1062 const ADReal p = pressure;
1063 const ADReal T = temperature;
1064 const ADReal X = Xnacl;
1065
1066 // FluidStateProperties data structure
1067 std::vector<FluidStateProperties> fsp(_num_phases, FluidStateProperties(_num_components));
1070
1071 // Calculate equilibrium mass fractions in the two-phase state
1072 ADReal Xco2, Yh2o;
1073 equilibriumMassFractions(p, T, X, Xco2, Yh2o);
1074
1075 // Save the mass fractions in the FluidStateMassFractions object
1076 const ADReal Yco2 = 1.0 - Yh2o;
1077 liquid.mass_fraction[_aqueous_fluid_component] = 1.0 - Xco2;
1078 liquid.mass_fraction[_gas_fluid_component] = Xco2;
1081
1082 // Gas properties
1083 gasProperties(pressure, temperature, fsp);
1084
1085 // Liquid properties
1086 const ADReal liquid_saturation = 1.0 - saturation;
1087 const ADReal liquid_pressure = p - _pc.capillaryPressure(liquid_saturation, qp);
1088 liquidProperties(liquid_pressure, T, X, fsp);
1089
1090 // The total mass fraction of ncg (z) can now be calculated
1091 const ADReal Z = (saturation * gas.density * Yco2 + liquid_saturation * liquid.density * Xco2) /
1092 (saturation * gas.density + liquid_saturation * liquid.density);
1093
1094 return Z.value();
1095}
1096
1097ADReal
1098PorousFlowBrineCO2::henryConstant(const ADReal & temperature, const ADReal & Xnacl) const
1099{
1100 using std::pow;
1101
1102 // Henry's constant for dissolution in water
1103 const ADReal Kh_h2o = _brine_fp.henryConstant(temperature, _co2_henry);
1104
1105 // The correction to salt is obtained through the salting out coefficient
1106 const std::vector<Real> b{1.19784e-1, -7.17823e-4, 4.93854e-6, -1.03826e-8, 1.08233e-11};
1107
1108 // Need temperature in Celsius
1109 const ADReal Tc = temperature - _T_c2k;
1110
1111 ADReal kb = 0.0;
1112 for (unsigned int i = 0; i < b.size(); ++i)
1113 kb += b[i] * pow(Tc, i);
1114
1115 // Need salt mass fraction in molality
1116 const ADReal xmol = Xnacl / (1.0 - Xnacl) / _Mnacl;
1117
1118 // Henry's constant and its derivative wrt temperature and salt mass fraction
1119 return Kh_h2o * pow(10.0, xmol * kb);
1120}
1121
1122ADReal
1123PorousFlowBrineCO2::enthalpyOfDissolutionGas(const ADReal & temperature, const ADReal & Xnacl) const
1124{
1125 // Henry's constant
1126 const ADReal Kh = henryConstant(temperature, Xnacl);
1127
1128 ADReal hdis = -_R * temperature * temperature * Kh.derivatives()[_Tidx] / Kh / _Mco2;
1129
1130 // Derivative of enthalpy of dissolution wrt temperature and xnacl requires the second
1131 // derivatives of Henry's constant. For simplicity, approximate these numerically
1132 const Real dT = temperature.value() * 1.0e-8;
1133 const ADReal T2 = temperature + dT;
1134 const ADReal Kh2 = henryConstant(T2, Xnacl);
1135
1136 const Real dhdis_dT =
1137 (-_R * T2 * T2 * Kh2.derivatives()[_Tidx] / Kh2 / _Mco2 - hdis).value() / dT;
1138
1139 const Real dX = Xnacl.value() * 1.0e-8;
1140 const ADReal X2 = Xnacl + dX;
1141 const ADReal Kh3 = henryConstant(temperature, X2);
1142
1143 const Real dhdis_dX =
1144 (-_R * temperature * temperature * Kh3.derivatives()[_Tidx] / Kh3 / _Mco2 - hdis).value() /
1145 dX;
1146
1147 hdis.derivatives() = temperature.derivatives() * dhdis_dT + Xnacl.derivatives() * dhdis_dX;
1148
1149 return hdis;
1150}
1151
1152ADReal
1154{
1155 // Linear fit to model of Duan and Sun (2003) (in kJ/mol)
1156 const ADReal delta_h = -58.3533 + 0.134519 * temperature;
1157
1158 // Convert to J/kg
1159 return delta_h * 1000.0 / _Mco2;
1160}
1161
1162void
1164 Real temperature, Real f0, Real df0, Real f1, Real df1, Real & value, Real & deriv) const
1165{
1166 // Coefficients of cubic polynomial
1167 const Real dT = _Tupper - _Tlower;
1168
1169 const Real a = f0;
1170 const Real b = df0 * dT;
1171 const Real c = 3.0 * (f1 - f0) - (2.0 * df0 + df1) * dT;
1172 const Real d = 2.0 * (f0 - f1) + (df0 + df1) * dT;
1173
1174 const Real t2 = temperature * temperature;
1175 const Real t3 = temperature * t2;
1176
1177 value = a + b * temperature + c * t2 + d * t3;
1178 deriv = b + 2.0 * c * temperature + 3.0 * d * t2;
1179}
1180
1181void
1182PorousFlowBrineCO2::checkVariables(Real pressure, Real temperature) const
1183{
1184 // The calculation of mass fractions is valid from 12C <= T <= 300C, and
1185 // pressure less than 60 MPa
1186 if (temperature < 285.15 || temperature > 573.15)
1187 mooseException(name() + ": temperature " + Moose::stringify(temperature) +
1188 " is outside range 285.15 K <= T <= 573.15 K");
1189
1190 if (pressure > 6.0e7)
1191 mooseException(name() + ": pressure " + Moose::stringify(pressure) +
1192 " must be less than 60 MPa");
1193}
DualNumber< Real, DNDerivativeType, true > ADReal
const std::vector< double > y
const double tol
const std::vector< double > x
ExpressionBuilder::EBTerm pow(const ExpressionBuilder::EBTerm &left, T exponent)
const Real p
const double T
Point xi
registerMooseObject("PorousFlowApp", PorousFlowBrineCO2)
FluidStatePhaseEnum
Phase state enum.
const std::string name
Definition Setup.h:21
void ErrorVector unsigned int
Brine (NaCl in H2O) fluid properties as a function of pressure (Pa), temperature (K) and NaCl mass fr...
virtual Real mu_from_p_T_X(Real pressure, Real temperature, Real xnacl) const override
virtual Real rho_from_p_T_X(Real pressure, Real temperature, Real xnacl) const override
FPADReal h_from_p_T_X(const FPADReal &pressure, const FPADReal &temperature, const FPADReal &xnacl) const
Real vaporPressure(Real temperature, Real xnacl) const
Brine vapour pressure From Haas, Physical properties of the coexisting phases and thermochemical prop...
Real henryConstant(Real temperature, const std::vector< Real > &coeffs) const
IAPWS formulation of Henry's law constant for dissolution in water (implemented in water FluidPropert...
virtual std::string fluidName() const override
Fluid name.
void addRequiredParam(const std::string &name, const std::string &doc_string)
void addParam(const std::string &name, const std::initializer_list< typename T::value_type > &value, const std::string &doc_string)
void addClassDescription(const std::string &doc_string)
void paramError(const std::string &param, Args... args) const
void mooseError(Args &&... args) const
Specialized class for brine and CO2 including calculation of mutual solubility of the two fluids usin...
void liquidProperties(const ADReal &pressure, const ADReal &temperature, const ADReal &Xnacl, std::vector< FluidStateProperties > &fsp) const
Thermophysical properties of the liquid state.
void funcABLowTemp(const ADReal &pressure, const ADReal &temperature, const ADReal &co2_density, ADReal &A, ADReal &B) const
ADReal saturation(const ADReal &pressure, const ADReal &temperature, const ADReal &Xnacl, const ADReal &Z, std::vector< FluidStateProperties > &fsp) const
Gas saturation in the two-phase region.
ADReal fugacityCoefficientCO2HighTemp(const ADReal &pressure, const ADReal &temperature, const ADReal &co2_density, const ADReal &xco2, const ADReal &yh2o) const
ADReal henryConstant(const ADReal &temperature, const ADReal &Xnacl) const
Henry's constant of dissolution of gas phase CO2 in brine.
const Real _Tlower
Temperature below which the Spycher, Pruess & Ennis-King (2003) model is used (K)
void gasProperties(const ADReal &pressure, const ADReal &temperature, std::vector< FluidStateProperties > &fsp) const
Thermophysical properties of the gaseous state.
const Real _Tupper
Temperature above which the Spycher & Pruess (2010) model is used (K)
const Real _invMh2o
Inverse of molar mass of H2O (mol/kg)
ADReal enthalpyOfDissolutionGas(const ADReal &temperature, const ADReal &Xnacl) const
Enthalpy of dissolution of gas phase CO2 in brine calculated using Henry's constant From Himmelblau,...
virtual void checkVariables(Real pressure, Real temperature) const
Check the input variables.
ADReal fugacityCoefficientH2OHighTemp(const ADReal &pressure, const ADReal &temperature, const ADReal &co2_density, const ADReal &xco2, const ADReal &yh2o) const
ADReal partialDensityCO2(const ADReal &temperature) const
Partial density of dissolved CO2 From Garcia, Density of aqueous solutions of CO2,...
const Real _Rbar
Molar gas constant in bar cm^3 /(K mol)
void fugacityCoefficientsHighTemp(const ADReal &pressure, const ADReal &temperature, const ADReal &co2_density, const ADReal &xco2, const ADReal &yh2o, ADReal &fco2, ADReal &fh2o) const
Fugacity coefficients for H2O and CO2 at elevated temperatures (100C < T <= 300C).
ADReal activityCoefficientHighTemp(const ADReal &temperature, const ADReal &Xnacl) const
Activity coefficient for CO2 in brine used in the elevated temperature formulation.
void solveEquilibriumMoleFractionHighTemp(Real pressure, Real temperature, Real Xnacl, Real co2_density, Real &xco2, Real &yh2o) const
Function to solve for yh2o and xco2 iteratively in the elevated temperature regime (T > 100C)
const Real _Mco2
Molar mass of CO2 (kg/mol)
void massFractions(const ADReal &pressure, const ADReal &temperature, const ADReal &Xnacl, const ADReal &Z, FluidStatePhaseEnum &phase_state, std::vector< FluidStateProperties > &fsp) const
Mass fractions of CO2 and H2O in both phases, as well as derivatives wrt PorousFlow variables.
void smoothCubicInterpolation(Real temperature, Real f0, Real df0, Real f1, Real df1, Real &value, Real &deriv) const
Cubic function to smoothly interpolate between the low temperature and elevated temperature models fo...
void funcABHighTemp(Real pressure, Real temperature, Real Xnacl, Real co2_density, Real xco2, Real yh2o, Real &A, Real &B) const
The function A (Eq.
const Real _Zmin
Minimum Z - below this value all CO2 will be dissolved.
const std::vector< Real > _co2_henry
Henry's coefficeients for CO2.
virtual std::string fluidStateName() const override
Name of FluidState.
void equilibriumMoleFractionsLowTemp(const ADReal &pressure, const ADReal &temperature, const ADReal &Xnacl, ADReal &xco2, ADReal &yh2o) const
Mole fractions of CO2 in brine and water vapor in CO2 at equilibrium in the low temperature regime (T...
const BrineFluidProperties & _brine_fp
Fluid properties UserObject for water.
void equilibriumMoleFractions(const ADReal &pressure, const ADReal &temperature, const ADReal &Xnacl, ADReal &xco2, ADReal &yh2o) const
Mole fractions of CO2 in brine and water vapor in CO2 at equilibrium.
PorousFlowBrineCO2(const InputParameters &parameters)
virtual Real totalMassFraction(Real pressure, Real temperature, Real Xnacl, Real saturation, unsigned int qp) const override
Total mass fraction of fluid component summed over all phases in the two-phase state for a specified ...
void equilibriumMassFractions(const ADReal &pressure, const ADReal &temperature, const ADReal &Xnacl, ADReal &Xco2, ADReal &Yh2o) const
Mass fractions of CO2 in brine and water vapor in CO2 at equilibrium.
ADReal equilibriumConstantCO2(const ADReal &temperature) const
Equilibrium constant for CO2 For temperatures 12C <= T <= 99C, uses Spycher, Pruess and Ennis-King (2...
void twoPhaseProperties(const ADReal &pressure, const ADReal &temperature, const ADReal &Xnacl, const ADReal &Z, unsigned int qp, std::vector< FluidStateProperties > &fsp) const
Gas and liquid properties in the two-phase region.
ADReal activityCoefficient(const ADReal &pressure, const ADReal &temperature, const ADReal &Xnacl) const
Activity coefficient for CO2 in brine.
const Real _Mh2o
Molar mass of water (kg/mol)
static InputParameters validParams()
const unsigned int _salt_component
Salt component index.
ADReal activityCoefficientCO2(const ADReal &temperature, const ADReal &xco2) const
Activity coefficient of CO2 Eq.
void fugacityCoefficientsLowTemp(const ADReal &pressure, const ADReal &temperature, const ADReal &co2_density, ADReal &fco2, ADReal &fh2o) const
Fugacity coefficients for H2O and CO2 for T <= 100C Eq.
const SinglePhaseFluidProperties & _co2_fp
Fluid properties UserObject for the CO2.
ADReal enthalpyOfDissolution(const ADReal &temperature) const
Enthalpy of dissolution of CO2 in brine calculated using linear fit to model of Duan and Sun,...
ADReal activityCoefficientH2O(const ADReal &temperature, const ADReal &xco2) const
Activity coefficient of H2O Eq.
void thermophysicalProperties(Real pressure, Real temperature, Real Xnacl, Real Z, unsigned int qp, std::vector< FluidStateProperties > &fsp) const override
Determines the complete thermophysical state of the system for a given set of primary variables.
ADReal equilibriumConstantH2O(const ADReal &temperature) const
Equilibrium constant for H2O For temperatures 12C <= T <= 99C, uses Spycher, Pruess and Ennis-King (2...
const Real _Mnacl
Molar mass of NaCL.
virtual Real capillaryPressure(Real saturation, unsigned qp=0) const
Capillary pressure is calculated as a function of true saturation.
unsigned int _num_components
Number of components.
const PorousFlowCapillaryPressure & _pc
Capillary pressure UserObject.
unsigned int _gas_phase_number
Phase number of the gas phase.
const Real _R
Universal gas constant (J/mol/K)
const unsigned int _aqueous_phase_number
Phase number of the aqueous phase.
FluidStateProperties _empty_fsp
Empty FluidStateProperties object.
const Real _T_c2k
Conversion from C to K.
void clearFluidStateProperties(std::vector< FluidStateProperties > &fsp) const
Clears the contents of the FluidStateProperties data structure.
unsigned int _num_phases
Number of phases.
Real vaporMassFraction(Real Z0, Real K0, Real K1) const
Solves Rachford-Rice equation to provide vapor mass fraction.
Compositional flash routines for miscible multiphase flow classes with multiple fluid components.
const unsigned int _Xidx
Index of derivative wrt salt mass fraction X.
unsigned int _gas_fluid_component
Fluid component number of the gas phase.
const unsigned int _pidx
Index of derivative wrt pressure.
const unsigned int _Tidx
Index of derivative wrt temperature.
const unsigned int _Zidx
Index of derivative wrt total mass fraction Z.
const unsigned int _aqueous_fluid_component
Fluid component number of the aqueous component.
void phaseState(Real Zi, Real Xi, Real Yi, FluidStatePhaseEnum &phase_state) const
Determines the phase state gven the total mass fraction and equilibrium mass fractions.
Common class for single phase fluid properties.
e e e e s T T T T T rho v v T e p T T virtual T std::string fluidName() const
Fluid name.
virtual void rho_mu_from_p_T(Real p, Real T, Real &rho, Real &mu) const
Combined methods.
std::string stringify(const T &t)
void derivInsert(SemiDynamicSparseNumberArray< Real, libMesh::dof_id_type, NWrapper< N > > &derivs, libMesh::dof_id_type index, Real value)
AD data structure to pass calculated thermophysical properties.
std::vector< ADReal > mass_fraction