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