https://mooseframework.inl.gov
Loading...
Searching...
No Matches
BrineFluidProperties.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
11
13
16{
18 params.addParam<UserObjectName>("water_fp",
19 "The name of the FluidProperties UserObject for water");
20 params.addClassDescription("Fluid properties for brine");
21 return params;
22}
23
25 : MultiComponentFluidProperties(parameters), _water_fp_derivs(true)
26{
27 // There are two possibilities to consider:
28 // 1) No water_fp has been supplied (in which case one is constructed)
29 // 2) A water_fp hase been supplied (in which case it is used)
30 // In both cases, though, a Water97FluidProperties UserObject must be added
31 // Note: this UserObject is only used to gain access to the Henry's constant
32 // formulation. All property calculations are performed using _water_fp
33 const std::string water_name = name() + ":water";
34 {
35 const std::string class_name = "Water97FluidProperties";
36 InputParameters params = _app.getFactory().getValidParams(class_name);
37 if (_tid == 0)
38 _fe_problem.addUserObject(class_name, water_name, params);
39 }
41
42 if (parameters.isParamSetByUser("water_fp"))
43 {
44 // SinglePhaseFluidPropertiesPT UserObject for water
45 _water_fp = &getUserObject<SinglePhaseFluidProperties>("water_fp");
46
47 // Check that a water userobject has actually been supplied
48 if (_water_fp->fluidName() != "water")
49 paramError("water_fp", "A water FluidProperties UserObject must be supplied");
50 }
51 else
52 {
53 // Construct a SinglePhaseFluidProperties UserObject for water
55 }
56
57 // SinglePhaseFluidProperties UserObject for NaCl
58 const std::string nacl_name = name() + ":nacl";
59 {
60 const std::string class_name = "NaClFluidProperties";
61 InputParameters params = _app.getFactory().getValidParams(class_name);
62 if (_tid == 0)
63 _fe_problem.addUserObject(class_name, nacl_name, params);
64 }
66
67 // Molar mass of NaCl and H20
70}
71
73
75BrineFluidProperties::getComponent(unsigned int component) const
76{
77 switch (component)
78 {
79 case WATER:
80 return *_water_fp;
81
82 case NACL:
83 return *_nacl_fp;
84
85 default:
86 mooseError("BrineFluidProperties::getComponent has been provided an incorrect component");
87 }
88}
89
90std::string
92{
93 return "brine";
94}
95
98{
99 return 1.0 / (xnacl / _Mnacl + (1.0 - xnacl) / _Mh2o);
100}
101
102Real
104{
105 return 1.0 / (xnacl / _Mnacl + (1.0 - xnacl) / _Mh2o);
106}
107
108Real
110{
111 return _Mnacl;
112}
113
114Real
116{
117 return _Mh2o;
118}
119
122 const FPADReal & temperature,
123 const FPADReal & xnacl) const
124{
125 using std::exp, std::sqrt;
126 // The correlation requires the pressure in bar, not Pa.
127 FPADReal pbar = pressure * 1.0e-5;
128 FPADReal pbar2 = pbar * pbar;
129 FPADReal pbar3 = pbar2 * pbar;
130
131 // The correlation requires mole fraction
132 const FPADReal Xnacl = massFractionToMoleFraction(xnacl);
133
134 const FPADReal n11 = -54.2958 - 45.7623 * exp(-9.44785e-4 * pbar);
135 const FPADReal n21 = -2.6142 - 2.39092e-4 * pbar;
136 const FPADReal n22 = 0.0356828 + 4.37235e-6 * pbar + 2.0566e-9 * pbar2;
137 const FPADReal n1x1 =
138 330.47 + 0.942876 * sqrt(pbar) + 0.0817193 * pbar - 2.47556e-8 * pbar2 + 3.45052e-10 * pbar3;
139 const FPADReal n2x1 = -0.0370751 + 0.00237723 * sqrt(pbar) + 5.42049e-5 * pbar +
140 5.84709e-9 * pbar2 - 5.99373e-13 * pbar3;
141 const FPADReal n12 = -n1x1 - n11;
142 const FPADReal n20 = 1.0 - n21 * sqrt(n22);
143 const FPADReal n23 = n2x1 - n20 - n21 * sqrt(1.0 + n22);
144
145 // The temperature Tv where the brine has the same molar volume as pure water
146 // Note: correlation uses temperature in Celcius
147 const FPADReal n1 = n1x1 + n11 * (1.0 - Xnacl) + n12 * (1.0 - Xnacl) * (1.0 - Xnacl);
148 const FPADReal n2 = n20 + n21 * sqrt(Xnacl + n22) + n23 * Xnacl;
149 const FPADReal Tv = n1 + n2 * (temperature - _T_c2k);
150
151 // The density of water at temperature Tv
152 // Note: convert Tv to Kelvin to calculate water density
153 FPADReal water_density;
155 {
156 Real rho, drho_dp, drho_dT;
157 _water_fp->rho_from_p_T(pressure.value(), Tv.value() + _T_c2k, rho, drho_dp, drho_dT);
158 water_density = rho;
159
160 water_density.derivatives() = pressure.derivatives() * drho_dp + Tv.derivatives() * drho_dT;
161 }
162 else
163 water_density = _water_fp->rho_from_p_T(pressure.value(), Tv.value() + _T_c2k);
164
165 // The brine density is given by the water density scaled by the ratio of
166 // brine molar mass to pure water molar mass
167 return water_density * molarMass(xnacl) / _Mh2o;
168}
169
170Real
171BrineFluidProperties::rho_from_p_T_X(Real pressure, Real temperature, Real xnacl) const
172{
173 // Initialise the AD value (no derivatives required)
174 FPADReal p = pressure;
175 FPADReal T = temperature;
176 FPADReal x = xnacl;
177
178 _water_fp_derivs = false;
179 FPADReal ad_rho = this->rho_from_p_T_X(p, T, x);
180
181 return ad_rho.value();
182}
183
184void
186 Real temperature,
187 Real xnacl,
188 Real & rho,
189 Real & drho_dp,
190 Real & drho_dT,
191 Real & drho_dx) const
192{
193 // Initialise the AD value and derivatives
194 FPADReal p = pressure;
195 Moose::derivInsert(p.derivatives(), 0, 1.0);
196 FPADReal T = temperature;
197 Moose::derivInsert(T.derivatives(), 1, 1.0);
198 FPADReal x = xnacl;
199 Moose::derivInsert(x.derivatives(), 2, 1.0);
200
201 _water_fp_derivs = true;
202 FPADReal ad_rho = this->rho_from_p_T_X(p, T, x);
203
204 rho = ad_rho.value();
205 drho_dp = ad_rho.derivatives()[0];
206 drho_dT = ad_rho.derivatives()[1];
207 drho_dx = ad_rho.derivatives()[2];
208}
209
210Real
211BrineFluidProperties::mu_from_p_T_X(Real pressure, Real temperature, Real xnacl) const
212{
213 // Correlation requires molal concentration (mol/kg)
214 const Real mol = massFractionToMolalConc(xnacl);
215 const Real mol2 = mol * mol;
216 const Real mol3 = mol2 * mol;
217
218 // Correlation requires temperature in C
219 const Real Tc = temperature - _T_c2k;
220
221 const Real a = 1.0 + 0.0816 * mol + 0.0122 * mol2 + 0.128e-3 * mol3 +
222 0.629e-3 * Tc * (1.0 - std::exp(-0.7 * mol));
223
224 const Real water_viscosity = _water_fp->mu_from_p_T(pressure, temperature);
225
226 return a * water_viscosity;
227}
228
229void
231 Real temperature,
232 Real xnacl,
233 Real & mu,
234 Real & dmu_dp,
235 Real & dmu_dT,
236 Real & dmu_dx) const
237{
238 // Viscosity of water and derivatives wrt pressure and temperature
239 Real muw, dmuw_dp, dmuw_dT;
240 _water_fp->mu_from_p_T(pressure, temperature, muw, dmuw_dp, dmuw_dT);
241
242 // Correlation requires molal concentration (mol/kg)
243 Real mol = massFractionToMolalConc(xnacl);
244 Real dmol_dx = 1.0 / ((1.0 - xnacl) * (1.0 - xnacl) * _Mnacl);
245 Real mol2 = mol * mol;
246 Real mol3 = mol2 * mol;
247
248 // Correlation requires temperature in C
249 Real Tc = temperature - _T_c2k;
250
251 Real a = 1.0 + 0.0816 * mol + 0.0122 * mol2 + 0.128e-3 * mol3 +
252 0.629e-3 * Tc * (1.0 - std::exp(-0.7 * mol));
253 Real da_dx =
254 (0.0816 + 0.0244 * mol + 3.84e-4 * mol2 + 4.403e-4 * Tc * std::exp(-0.7 * mol)) * dmol_dx;
255 Real da_dT = 0.629e-3 * (1.0 - std::exp(-0.7 * mol));
256
257 mu = a * muw;
258 dmu_dp = a * dmuw_dp;
259 dmu_dx = da_dx * muw;
260 dmu_dT = da_dT * muw + a * dmuw_dT;
261}
262
265 const FPADReal & temperature,
266 const FPADReal & xnacl) const
267{
268 using std::sqrt;
269
270 FPADReal q1, q2, q10, q11, q12, q20, q21, q22, q23, q1x1, q2x1, Th;
271
272 // The correlation requires the pressure in bar, not Pa.
273 const FPADReal pbar = pressure * 1.0e-5;
274 const FPADReal pbar2 = pbar * pbar;
275
276 // The correlation requires mole fraction
277 const FPADReal Xnacl = massFractionToMoleFraction(xnacl);
278
279 q11 = -32.1724 + 0.0621255 * pbar;
280 q21 = -1.69513 - 4.52781e-4 * pbar - 6.04279e-8 * pbar2;
281 q22 = 0.0612567 + 1.88082e-5 * pbar;
282
283 q1x1 = 47.9048 - 9.36994e-3 * pbar + 6.51059e-6 * pbar2;
284 q2x1 = 0.241022 + 3.45087e-5 * pbar - 4.28356e-9 * pbar2;
285
286 q12 = -q11 - q1x1;
287 q10 = q1x1;
288
289 q20 = 1.0 - q21 * sqrt(q22);
290 q23 = q2x1 - q20 - q21 * sqrt(1.0 + q22);
291
292 q1 = q10 + q11 * (1.0 - Xnacl) + q12 * (1.0 - Xnacl) * (1.0 - Xnacl);
293 q2 = q20 + q21 * sqrt(Xnacl + q22) + q23 * Xnacl;
294 // The temperature Th where the brine has the same enthalpy as pure water
295 // Note: correlation uses temperature in Celcius
296 Th = q1 + q2 * (temperature - _T_c2k);
297
298 // The brine enthalpy is then given by the enthalpy of water at temperature Th
299 // Note: water enthalpy requires temperature in Kelvin
300 FPADReal enthalpy;
302 {
303 Real h, dh_dp, dh_dT;
304 _water_fp->h_from_p_T(pressure.value(), Th.value() + _T_c2k, h, dh_dp, dh_dT);
305 enthalpy = h;
306
307 enthalpy.derivatives() = pressure.derivatives() * dh_dp + Th.derivatives() * dh_dT;
308 }
309 else
310 enthalpy = _water_fp->h_from_p_T(pressure.value(), Th.value() + _T_c2k);
311
312 return enthalpy;
313}
314
315Real
316BrineFluidProperties::h_from_p_T_X(Real pressure, Real temperature, Real xnacl) const
317{
318 // Initialise the AD value (no derivatives required)
319 FPADReal p = pressure;
320 FPADReal T = temperature;
321 FPADReal x = xnacl;
322
323 _water_fp_derivs = false;
324 return h_from_p_T_X(p, T, x).value();
325}
326
327void
329 Real temperature,
330 Real xnacl,
331 Real & h,
332 Real & dh_dp,
333 Real & dh_dT,
334 Real & dh_dx) const
335{
336 // Initialise the AD value and derivatives
337 FPADReal p = pressure;
338 Moose::derivInsert(p.derivatives(), 0, 1.0);
339 FPADReal T = temperature;
340 Moose::derivInsert(T.derivatives(), 1, 1.0);
341 FPADReal x = xnacl;
342 Moose::derivInsert(x.derivatives(), 2, 1.0);
343
344 _water_fp_derivs = true;
345 FPADReal ad_h = h_from_p_T_X(p, T, x);
346
347 h = ad_h.value();
348 dh_dp = ad_h.derivatives()[0];
349 dh_dT = ad_h.derivatives()[1];
350 dh_dx = ad_h.derivatives()[2];
351}
352
353Real
354BrineFluidProperties::cp_from_p_T_X(Real pressure, Real temperature, Real xnacl) const
355{
356 Real q1, q2, q10, q11, q12, q20, q21, q22, q23, q1x1, q2x1, Th;
357
358 // The correlation requires the pressure in bar, not Pa.
359 Real pbar = pressure * 1.0e-5;
360 Real pbar2 = pbar * pbar;
361
362 // The correlation requires mole fraction
363 Real Xnacl = massFractionToMoleFraction(xnacl);
364
365 q11 = -32.1724 + 0.0621255 * pbar;
366 q21 = -1.69513 - 4.52781e-4 * pbar - 6.04279e-8 * pbar2;
367 q22 = 0.0612567 + 1.88082e-5 * pbar;
368
369 q1x1 = 47.9048 - 9.36994e-3 * pbar + 6.51059e-6 * pbar2;
370 q2x1 = 0.241022 + 3.45087e-5 * pbar - 4.28356e-9 * pbar2;
371
372 q12 = -q11 - q1x1;
373 q10 = q1x1;
374
375 q20 = 1.0 - q21 * std::sqrt(q22);
376 q23 = q2x1 - q20 - q21 * std::sqrt(1.0 + q22);
377
378 q1 = q10 + q11 * (1.0 - Xnacl) + q12 * (1.0 - Xnacl) * (1.0 - Xnacl);
379 q2 = q20 + q21 * std::sqrt(Xnacl + q22) + q23 * Xnacl;
380 // The temperature Th where the brine has the same isobaric heat capacity
381 // as pure water. Note: correlation uses temperature in Celcius
382 Th = q1 + q2 * (temperature - _T_c2k);
383
384 // The brine isobaric heat capacity is then given by the isobaric heat
385 // capacity of water at temperature Th multiplied by q2
386 // Note: water isobaric heat capacity requires temperature in Kelvin
387 return q2 * _water_fp->cp_from_p_T(pressure, Th + _T_c2k);
388}
389
392 const FPADReal & temperature,
393 const FPADReal & xnacl) const
394{
395 FPADReal enthalpy = h_from_p_T_X(pressure, temperature, xnacl);
396 FPADReal density = rho_from_p_T_X(pressure, temperature, xnacl);
397
398 return enthalpy - pressure / density;
399}
400
401Real
402BrineFluidProperties::e_from_p_T_X(Real pressure, Real temperature, Real xnacl) const
403{
404 Real enthalpy = h_from_p_T_X(pressure, temperature, xnacl);
405 Real density = rho_from_p_T_X(pressure, temperature, xnacl);
406
407 return enthalpy - pressure / density;
408}
409
410void
412 Real temperature,
413 Real xnacl,
414 Real & e,
415 Real & de_dp,
416 Real & de_dT,
417 Real & de_dx) const
418{
419 // Initialise the AD value and derivatives
420 FPADReal p = pressure;
421 Moose::derivInsert(p.derivatives(), 0, 1.0);
422 FPADReal T = temperature;
423 Moose::derivInsert(T.derivatives(), 1, 1.0);
424 FPADReal x = xnacl;
425 Moose::derivInsert(x.derivatives(), 2, 1.0);
426
427 _water_fp_derivs = true;
428 FPADReal ad_e = e_from_p_T_X(p, T, x);
429
430 e = ad_e.value();
431 de_dp = ad_e.derivatives()[0];
432 de_dT = ad_e.derivatives()[1];
433 de_dx = ad_e.derivatives()[2];
434}
435
436Real
437BrineFluidProperties::k_from_p_T_X(Real pressure, Real temperature, Real xnacl) const
438{
439 // Correlation requires molal concentration (mol/kg)
440 Real mol = massFractionToMolalConc(xnacl);
441 // Correlation requires temperature in C
442 Real Tc = temperature - _T_c2k;
443
444 Real S = 100.0 * _Mnacl * mol / (1.0 + _Mnacl * mol);
445 Real lambdaw = _water_fp->k_from_p_T(pressure, temperature);
446 Real lambda = 1.0 - (2.3434e-3 - 7.924e-6 * Tc + 3.924e-8 * Tc * Tc) * S +
447 (1.06e-5 - 2.0e-8 * Tc - 1.2e-10 * Tc * Tc) * S * S;
448
449 return lambda * lambdaw;
450}
451
452Real
453BrineFluidProperties::vaporPressure(Real temperature, Real xnacl) const
454{
455 // Correlation requires molal concentration (mol/kg)
456 Real mol = massFractionToMolalConc(xnacl);
457 Real mol2 = mol * mol;
458 Real mol3 = mol2 * mol;
459
460 Real a = 1.0 + 5.93582e-6 * mol - 5.19386e-5 * mol2 + 1.23156e-5 * mol3;
461 Real b = 1.1542e-6 * mol + 1.41254e-7 * mol2 - 1.92476e-8 * mol3 - 1.70717e-9 * mol * mol3 +
462 1.0539e-10 * mol2 * mol3;
463
464 // The temperature of pure water at the same pressure as the brine is given by
465 Real th20 = std::exp(std::log(temperature) / (a + b * temperature));
466
467 // The brine vapour pressure is then found by evaluating the saturation pressure for pure water
468 // using this effective temperature
469 return _water_fp->vaporPressure(th20);
470}
471
472Real
474{
475 // This correlation requires temperature in Celcius
476 Real Tc = temperature - _T_c2k;
477
478 return (26.18 + 7.2e-3 * Tc + 1.06e-4 * Tc * Tc) / 100.0;
479}
480
481Real
483{
484 return xnacl / ((1.0 - xnacl) * _Mnacl);
485}
486
487Real
489{
490 // The average molar mass of brine from the mass fraction
491 Real Mbrine = molarMass(xnacl);
492 // The mole fraction is then
493 return xnacl * Mbrine / _Mnacl;
494}
495
498{
499 // The average molar mass of brine from the mass fraction
500 FPADReal Mbrine = molarMass(xnacl);
501 // The mole fraction is then
502 return xnacl * Mbrine / _Mnacl;
503}
504
505Real
506BrineFluidProperties::henryConstant(Real temperature, const std::vector<Real> & coeffs) const
507{
508 return _water97_fp->henryConstant(temperature, coeffs);
509}
510
511void
513 const std::vector<Real> & coeffs,
514 Real & Kh,
515 Real & dKh_dT) const
516{
517 _water97_fp->henryConstant(temperature, coeffs, Kh, dKh_dT);
518}
519
520ADReal
522 const std::vector<Real> & coeffs) const
523{
524 Real Kh, dKh_dT;
525 henryConstant(temperature.value(), coeffs, Kh, dKh_dT);
526
527 ADReal henry = Kh;
528 henry.derivatives() = temperature.derivatives() * dKh_dT;
529
530 return henry;
531}
DualNumber< Real, DNDerivativeType, true > ADReal
registerMooseObject("FluidPropertiesApp", BrineFluidProperties)
const std::vector< double > x
DualNumber< Real, DNDerivativeSize< 5 > > FPADReal
const double mu
const double rho
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
Real massFractionToMolalConc(Real xnacl) const
Conversion from mass fraction to molal concentration (molality)
FPADReal e_from_p_T_X(const FPADReal &pressure, const FPADReal &temperature, const FPADReal &xnacl) const
const SinglePhaseFluidProperties * _nacl_fp
NaClFluidProperties UserObject.
Real molarMassNaCl() const
NaCl molar mass.
FPADReal h_from_p_T_X(const FPADReal &pressure, const FPADReal &temperature, const FPADReal &xnacl) const
virtual Real k_from_p_T_X(Real pressure, Real temperature, Real xnacl) const override
Real massFractionToMoleFraction(Real xnacl) const
Conversion from mass fraction to mole fraction.
Real _Mh2o
Molar mass of water (H2O) (kg/mol)
Real haliteSolubility(Real temperature) const
Solubility of halite (solid NaCl) in water Originally from Potter et al., A new method for determinin...
static const unsigned int NACL
BrineFluidProperties(const InputParameters &parameters)
Real vaporPressure(Real temperature, Real xnacl) const
Brine vapour pressure From Haas, Physical properties of the coexisting phases and thermochemical prop...
const SinglePhaseFluidProperties * _water_fp
Water97FluidProperties UserObject.
Real molarMassH2O() const
H2O molar mass.
static InputParameters validParams()
static const unsigned int WATER
Fluid component numbers for water and NaCl.
virtual Real cp_from_p_T_X(Real pressure, Real temperature, Real xnacl) const override
virtual const SinglePhaseFluidProperties & getComponent(unsigned int component) const override
Get UserObject for specified component.
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...
bool _water_fp_derivs
Flag to indicate whether to calculate derivatives in water_fp.
Real molarMass(Real xnacl) const
Average molar mass of brine.
const Water97FluidProperties * _water97_fp
Water97FluidProperties UserObject (for Henry's law)
Real _Mnacl
Molar mass of NaCl (kg/mol)
virtual std::string fluidName() const override
Fluid name.
T & getUserObject(const std::string &name, unsigned int tid=0) const
virtual std::vector< std::shared_ptr< UserObject > > addUserObject(const std::string &user_object_name, const std::string &name, InputParameters &parameters)
InputParameters getValidParams(const std::string &name) const
const Real _T_c2k
Conversion of temperature from Celsius to Kelvin.
bool isParamSetByUser(const std::string &name) const
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)
Factory & getFactory()
const InputParameters & parameters() const
const std::string & name() const
void paramError(const std::string &param, Args... args) const
void mooseError(Args &&... args) const
Common class for multiple component fluid properties using a pressure and temperature formulation.
Common class for single phase fluid properties.
virtual Real vaporPressure(Real T) const
Vapor pressure.
virtual Real molarMass() const
Molar mass [kg/mol].
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.
FEProblemBase & _fe_problem
Water (H2O) fluid properties as a function of pressure (Pa) and temperature (K) from IAPWS-IF97: Revi...
Real henryConstant(Real temperature, const std::vector< Real > &coeffs) const
IAPWS formulation of Henry's law constant for dissolution in water From Guidelines on the Henry's con...
void derivInsert(SemiDynamicSparseNumberArray< Real, libMesh::dof_id_type, NWrapper< N > > &derivs, libMesh::dof_id_type index, Real value)