https://mooseframework.inl.gov
CO2FluidProperties.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 "CO2FluidProperties.h"
11 #include "BrentsMethod.h"
12 #include "Conversion.h"
13 #include "MathUtils.h"
14 #include "libmesh/utility.h"
15 
16 registerMooseObject("FluidPropertiesApp", CO2FluidProperties);
17 
20 {
22  params.addClassDescription(
23  "Fluid properties for carbon dioxide (CO2) using the Span & Wagner EOS");
24  return params;
25 }
26 
28  : HelmholtzFluidProperties(parameters)
29 {
30 }
31 
33 
34 std::string
36 {
37  return "co2";
38 }
39 
40 Real
42 {
43  return _Mco2;
44 }
45 
46 Real
48 {
49  return _critical_pressure;
50 }
51 
52 Real
54 {
55  return _critical_temperature;
56 }
57 
58 Real
60 {
61  return _critical_density;
62 }
63 
64 Real
66 {
68 }
69 
70 Real
72 {
74 }
75 
76 Real
78 {
80  throw MooseException("Temperature is below the triple point temperature in " + name() +
81  ": meltingPressure()");
82 
84 
85  return _triple_point_pressure *
86  (1.0 + 1955.539 * (Tstar - 1.0) + 2055.4593 * Utility::pow<2>(Tstar - 1.0));
87 }
88 
89 Real
91 {
93  throw MooseException("Temperature is above the triple point temperature in " + name() +
94  ": sublimationPressure()");
95 
97 
99  std::exp((-14.740846 * (1.0 - Tstar) + 2.4327015 * std::pow(1.0 - Tstar, 1.9) -
100  5.3061778 * std::pow(1.0 - Tstar, 2.9)) /
101  Tstar);
102 
103  return pressure;
104 }
105 
106 Real
108 {
109  if (temperature < _triple_point_temperature || temperature > _critical_temperature)
110  throw MooseException("Temperature is out of range in " + name() + ": vaporPressure()");
111 
113 
114  Real logpressure =
115  (-7.0602087 * (1.0 - Tstar) + 1.9391218 * std::pow(1.0 - Tstar, 1.5) -
116  1.6463597 * Utility::pow<2>(1.0 - Tstar) - 3.2995634 * Utility::pow<4>(1.0 - Tstar)) /
117  Tstar;
118 
119  return _critical_pressure * std::exp(logpressure);
120 }
121 
122 void
123 CO2FluidProperties::vaporPressure(Real, Real &, Real &) const
124 {
125  mooseError("vaporPressure() is not implemented");
126 }
127 
128 Real
130 {
131  if (temperature < _triple_point_temperature || temperature > _critical_temperature)
132  throw MooseException("Temperature is out of range in " + name() + ": saturatedLiquiDensity()");
133 
135 
136  Real logdensity = 1.9245108 * std::pow(1.0 - Tstar, 0.34) -
137  0.62385555 * std::pow(1.0 - Tstar, 0.5) -
138  0.32731127 * std::pow(1.0 - Tstar, 10.0 / 6.0) +
139  0.39245142 * std::pow(1.0 - Tstar, 11.0 / 6.0);
140 
141  return _critical_density * std::exp(logdensity);
142 }
143 
144 Real
146 {
147  if (temperature < _triple_point_temperature || temperature > _critical_temperature)
148  throw MooseException("Temperature is out of range in " + name() + ": saturatedVaporDensity()");
149 
151 
152  Real logdensity =
153  (-1.7074879 * std::pow(1.0 - Tstar, 0.34) - 0.82274670 * std::pow(1.0 - Tstar, 0.5) -
154  4.6008549 * (1.0 - Tstar) - 10.111178 * std::pow(1.0 - Tstar, 7.0 / 3.0) -
155  29.742252 * std::pow(1.0 - Tstar, 14.0 / 3.0));
156 
157  return _critical_density * std::exp(logdensity);
158 }
159 
160 Real
161 CO2FluidProperties::alpha(Real delta, Real tau) const
162 {
163  // Ideal gas component of the Helmholtz free energy
164  Real sum0 = 0.0;
165  for (std::size_t i = 0; i < _a0.size(); ++i)
166  sum0 += _a0[i] * std::log(1.0 - std::exp(-_theta0[i] * tau));
167 
168  Real phi0 = std::log(delta) + 8.37304456 - 3.70454304 * tau + 2.5 * std::log(tau) + sum0;
169 
170  // Residual component of the Helmholtz free energy
171  Real theta, Delta, Psi;
172  Real phir = 0.0;
173  for (std::size_t i = 0; i < _n1.size(); ++i)
174  phir += _n1[i] * MathUtils::pow(delta, _d1[i]) * std::pow(tau, _t1[i]);
175 
176  for (std::size_t i = 0; i < _n2.size(); ++i)
177  phir += _n2[i] * MathUtils::pow(delta, _d2[i]) * std::pow(tau, _t2[i]) *
178  std::exp(-MathUtils::pow(delta, _c2[i]));
179 
180  for (std::size_t i = 0; i < _n3.size(); ++i)
181  phir += _n3[i] * MathUtils::pow(delta, _d3[i]) * MathUtils::pow(tau, _t3[i]) *
182  std::exp(-_alpha3[i] * Utility::pow<2>(delta - _eps3[i]) -
183  _beta3[i] * Utility::pow<2>(tau - _gamma3[i]));
184 
185  for (std::size_t i = 0; i < _n4.size(); ++i)
186  {
187  theta = 1.0 - tau + _A4[i] * std::pow(Utility::pow<2>(delta - 1.0), 1.0 / (2.0 * _beta4[i]));
188  Delta = Utility::pow<2>(theta) + _B4[i] * std::pow(Utility::pow<2>(delta - 1.0), _a4[i]);
189  Psi = std::exp(-_C4[i] * Utility::pow<2>(delta - 1.0) - _D4[i] * Utility::pow<2>(tau - 1.0));
190  phir += _n4[i] * std::pow(Delta, _b4[i]) * delta * Psi;
191  }
192 
193  // The Helmholtz free energy is the sum of these components
194  return phi0 + phir;
195 }
196 
197 Real
199 {
200  // Derivative of the ideal gas component wrt gamma
201  Real dphi0dd = 1.0 / delta;
202 
203  // Derivative of the residual component wrt gamma
204  Real theta, Delta, Psi, dDelta_dd, dPsi_dd;
205  Real dphirdd = 0.0;
206 
207  for (std::size_t i = 0; i < _n1.size(); ++i)
208  dphirdd += _n1[i] * _d1[i] * MathUtils::pow(delta, _d1[i] - 1.0) * std::pow(tau, _t1[i]);
209 
210  for (std::size_t i = 0; i < _n2.size(); ++i)
211  dphirdd += _n2[i] * std::exp(-MathUtils::pow(delta, _c2[i])) *
212  (MathUtils::pow(delta, _d2[i] - 1.0) * std::pow(tau, _t2[i]) *
213  (_d2[i] - _c2[i] * MathUtils::pow(delta, _c2[i])));
214 
215  for (std::size_t i = 0; i < _n3.size(); ++i)
216  dphirdd += _n3[i] * MathUtils::pow(delta, _d3[i]) * MathUtils::pow(tau, _t3[i]) *
217  std::exp(-_alpha3[i] * Utility::pow<2>(delta - _eps3[i]) -
218  _beta3[i] * Utility::pow<2>(tau - _gamma3[i])) *
219  (_d3[i] / delta - 2.0 * _alpha3[i] * (delta - _eps3[i]));
220 
221  for (std::size_t i = 0; i < _n4.size(); ++i)
222  {
223  theta = 1.0 - tau + _A4[i] * std::pow(Utility::pow<2>(delta - 1.0), 1.0 / (2.0 * _beta4[i]));
224  Delta = Utility::pow<2>(theta) + _B4[i] * std::pow(Utility::pow<2>(delta - 1.0), _a4[i]);
225  Psi = std::exp(-_C4[i] * Utility::pow<2>(delta - 1.0) - _D4[i] * Utility::pow<2>(tau - 1.0));
226  dPsi_dd = -2.0 * _C4[i] * (delta - 1.0) * Psi;
227  dDelta_dd = (delta - 1.0) *
228  (_A4[i] * theta * 2.0 / _beta4[i] *
229  std::pow(Utility::pow<2>(delta - 1.0), 1.0 / (2.0 * _beta4[i]) - 1.0) +
230  2.0 * _B4[i] * _a4[i] * std::pow(Utility::pow<2>(delta - 1.0), _a4[i] - 1.0));
231 
232  dphirdd += _n4[i] * (std::pow(Delta, _b4[i]) * (Psi + delta * dPsi_dd) +
233  _b4[i] * std::pow(Delta, _b4[i] - 1.0) * dDelta_dd * delta * Psi);
234  }
235 
236  // The derivative of the free energy wrt delta is the sum of these components
237  return dphi0dd + dphirdd;
238 }
239 
240 Real
242 {
243  // Derivative of the ideal gas component wrt tau
244  Real sum0 = 0.0;
245  for (std::size_t i = 0; i < _a0.size(); ++i)
246  sum0 += _a0[i] * _theta0[i] * (1.0 / (1.0 - std::exp(-_theta0[i] * tau)) - 1.0);
247 
248  Real dphi0dt = -3.70454304 + 2.5 / tau + sum0;
249 
250  // Derivative of the residual component wrt tau
251  Real theta, Delta, Psi, dDelta_dt, dPsi_dt;
252  Real dphirdt = 0.0;
253  for (std::size_t i = 0; i < _n1.size(); ++i)
254  dphirdt += _n1[i] * _t1[i] * MathUtils::pow(delta, _d1[i]) * std::pow(tau, _t1[i] - 1.0);
255 
256  for (std::size_t i = 0; i < _n2.size(); ++i)
257  dphirdt += _n2[i] * _t2[i] * MathUtils::pow(delta, _d2[i]) * std::pow(tau, _t2[i] - 1.0) *
258  std::exp(-MathUtils::pow(delta, _c2[i]));
259 
260  for (std::size_t i = 0; i < _n3.size(); ++i)
261  dphirdt += _n3[i] * MathUtils::pow(delta, _d3[i]) * MathUtils::pow(tau, _t3[i]) *
262  std::exp(-_alpha3[i] * Utility::pow<2>(delta - _eps3[i]) -
263  _beta3[i] * Utility::pow<2>(tau - _gamma3[i])) *
264  (_t3[i] / tau - 2.0 * _beta3[i] * (tau - _gamma3[i]));
265 
266  for (std::size_t i = 0; i < _n4.size(); ++i)
267  {
268  theta = 1.0 - tau + _A4[i] * std::pow(Utility::pow<2>(delta - 1.0), 1.0 / (2.0 * _beta4[i]));
269  Delta = Utility::pow<2>(theta) + _B4[i] * std::pow(Utility::pow<2>(delta - 1.0), _a4[i]);
270  Psi = std::exp(-_C4[i] * Utility::pow<2>(delta - 1.0) - _D4[i] * Utility::pow<2>(tau - 1.0));
271  dDelta_dt = -2.0 * theta * _b4[i] * std::pow(Delta, _b4[i] - 1.0);
272  dPsi_dt = -2.0 * _D4[i] * (tau - 1.0) * Psi;
273 
274  dphirdt += _n4[i] * delta * (Psi * dDelta_dt + std::pow(Delta, _b4[i]) * dPsi_dt);
275  }
276 
277  // The derivative of the free energy wrt tau is the sum of these components
278  return dphi0dt + dphirdt;
279 }
280 
281 Real
283 {
284  // Second derivative of the ideal gas component wrt gamma
285  Real d2phi0dd2 = -1.0 / delta / delta;
286 
287  // Second derivative of the residual component wrt gamma
288  Real d2phirdd2 = 0.0;
289  Real theta, Delta, Psi, dDelta_dd, dPsi_dd, d2Delta_dd2, d2Psi_dd2;
290 
291  for (std::size_t i = 0; i < _n1.size(); ++i)
292  d2phirdd2 += _n1[i] * _d1[i] * (_d1[i] - 1.0) * MathUtils::pow(delta, _d1[i] - 2) *
293  std::pow(tau, _t1[i]);
294 
295  for (std::size_t i = 0; i < _n2.size(); ++i)
296  d2phirdd2 += _n2[i] * std::exp(-MathUtils::pow(delta, _c2[i])) *
297  MathUtils::pow(delta, _d2[i] - 2) * std::pow(tau, _t2[i]) *
298  ((_d2[i] - _c2[i] * MathUtils::pow(delta, _c2[i])) *
299  (_d2[i] - 1.0 - _c2[i] * MathUtils::pow(delta, _c2[i])) -
300  _c2[i] * _c2[i] * MathUtils::pow(delta, _c2[i]));
301 
302  for (std::size_t i = 0; i < _n3.size(); ++i)
303  d2phirdd2 +=
304  _n3[i] * MathUtils::pow(tau, _t3[i]) *
305  std::exp(-_alpha3[i] * Utility::pow<2>(delta - _eps3[i]) -
306  _beta3[i] * Utility::pow<2>(tau - _gamma3[i])) *
307  (-2.0 * _alpha3[i] * MathUtils::pow(delta, _d3[i]) +
308  4.0 * _alpha3[i] * _alpha3[i] * MathUtils::pow(delta, _d3[i]) *
309  Utility::pow<2>(delta - _eps3[i]) -
310  4.0 * _d3[i] * _alpha3[i] * MathUtils::pow(delta, _d3[i] - 1.0) * (delta - _eps3[i]) +
311  _d3[i] * (_d3[i] - 1.0) * MathUtils::pow(delta, _d3[i] - 2.0));
312 
313  for (std::size_t i = 0; i < _n4.size(); ++i)
314  {
315  theta = 1.0 - tau + _A4[i] * std::pow(Utility::pow<2>(delta - 1.0), 1.0 / (2.0 * _beta4[i]));
316  Delta = Utility::pow<2>(theta) + _B4[i] * std::pow(Utility::pow<2>(delta - 1.0), _a4[i]);
317  Psi = std::exp(-_C4[i] * Utility::pow<2>(delta - 1.0) - _D4[i] * Utility::pow<2>(tau - 1.0));
318  dPsi_dd = -2.0 * _C4[i] * (delta - 1.0) * Psi;
319  dDelta_dd = (delta - 1.0) *
320  (_A4[i] * theta * 2.0 / _beta4[i] *
321  std::pow(Utility::pow<2>(delta - 1.0), 1.0 / (2.0 * _beta4[i]) - 1.0) +
322  2.0 * _B4[i] * _a4[i] * std::pow(Utility::pow<2>(delta - 1.0), _a4[i] - 1.0));
323  d2Psi_dd2 = 3.0 * _D4[i] * Psi * (2.0 * _C4[i] * Utility::pow<2>(delta - 1.0) - 1.0);
324  d2Delta_dd2 = 1.0 / (delta - 1.0) * dDelta_dd +
325  (delta - 1.0) * (delta - 1.0) *
326  (4.0 * _B4[i] * _a4[i] * (_a4[i] - 1.0) *
327  std::pow(Utility::pow<2>(delta - 1.0), _a4[i] - 2.0) +
328  2.0 * _A4[i] * _A4[i] *
329  Utility::pow<2>(std::pow(Utility::pow<2>(delta - 1.0),
330  1.0 / (2.0 * _beta4[i]) - 1.0)) /
331  _beta4[i] / _beta4[i] +
332  (4.0 / _beta4[i]) * _A4[i] * theta * (1.0 / (2.0 * _beta4[i]) - 1.0) *
333  std::pow(Utility::pow<2>(delta - 1.0), 1.0 / (2.0 * _beta4[i]) - 2.0));
334  d2phirdd2 +=
335  _n4[i] *
336  (std::pow(Delta, _b4[i]) * (2.0 * dPsi_dd + delta * d2Psi_dd2) +
337  2.0 * _b4[i] * std::pow(Delta, _b4[i] - 1.0) * dDelta_dd * (Psi + delta * dPsi_dd) +
338  _b4[i] *
339  (std::pow(Delta, _b4[i] - 1.0) * d2Delta_dd2 +
340  (_b4[i] - 1.0) * std::pow(Delta, _b4[i] - 2.0) * Utility::pow<2>(dDelta_dd)) *
341  delta * Psi);
342  }
343  // The second derivative of the free energy wrt delta is the sum of these components
344  return d2phi0dd2 + d2phirdd2;
345 }
346 
347 Real
349 {
350  // Second derivative of the ideal gas component wrt tau
351  Real sum0 = 0.0;
352  for (std::size_t i = 0; i < _a0.size(); ++i)
353  sum0 += _a0[i] * _theta0[i] * _theta0[i] * std::exp(-_theta0[i] * tau) /
354  Utility::pow<2>(1.0 - std::exp(-_theta0[i] * tau));
355 
356  Real d2phi0dt2 = -2.5 / tau / tau - sum0;
357 
358  // Second derivative of the residual component wrt tau
359  Real d2phirdt2 = 0.0;
360  Real theta, Delta, Psi, dPsi_dt, dDelta_dt, d2Delta_dt2, d2Psi_dt2;
361 
362  for (std::size_t i = 0; i < _n1.size(); ++i)
363  d2phirdt2 += _n1[i] * _t1[i] * (_t1[i] - 1.0) * MathUtils::pow(delta, _d1[i]) *
364  std::pow(tau, _t1[i] - 2.0);
365 
366  for (std::size_t i = 0; i < _n2.size(); ++i)
367  d2phirdt2 += _n2[i] * _t2[i] * (_t2[i] - 1.0) * MathUtils::pow(delta, _d2[i]) *
368  std::exp(-MathUtils::pow(delta, _c2[i])) * std::pow(tau, _t2[i] - 2.0);
369 
370  for (std::size_t i = 0; i < _n3.size(); ++i)
371  d2phirdt2 += _n3[i] * MathUtils::pow(delta, _d3[i]) * MathUtils::pow(tau, _t3[i]) *
372  std::exp(-_alpha3[i] * Utility::pow<2>(delta - _eps3[i]) -
373  _beta3[i] * Utility::pow<2>(tau - _gamma3[i])) *
374  (Utility::pow<2>(_t3[i] / tau - 2.0 * _beta3[i] * (tau - _gamma3[i])) -
375  _t3[i] / tau / tau - 2.0 * _beta3[i]);
376 
377  for (std::size_t i = 0; i < _n4.size(); ++i)
378  {
379  theta = 1.0 - tau + _A4[i] * std::pow(Utility::pow<2>(delta - 1.0), 1.0 / (2.0 * _beta4[i]));
380  Delta = Utility::pow<2>(theta) + _B4[i] * std::pow(Utility::pow<2>(delta - 1.0), _a4[i]);
381  Psi = std::exp(-_C4[i] * Utility::pow<2>(delta - 1.0) - _D4[i] * Utility::pow<2>(tau - 1.0));
382  dDelta_dt = -2.0 * theta * _b4[i] * std::pow(Delta, _b4[i] - 1.0);
383  d2Delta_dt2 = 2.0 * _b4[i] * std::pow(Delta, _b4[i] - 1.0) +
384  4.0 * theta * theta * _b4[i] * (_b4[i] - 1.0) * std::pow(Delta, _b4[i] - 2.0);
385  dPsi_dt = -2.0 * _D4[i] * (tau - 1.0) * Psi;
386  d2Psi_dt2 = 2.0 * _D4[i] * (2.0 * _D4[i] * (tau - 1.0) * (tau - 1.0) - 1.0) * Psi;
387  d2phirdt2 +=
388  _n4[i] * delta *
389  (Psi * d2Delta_dt2 + 2.0 * dDelta_dt * dPsi_dt + std::pow(Delta, _b4[i]) * d2Psi_dt2);
390  }
391 
392  // The second derivative of the free energy wrt tau is the sum of these components
393  return d2phi0dt2 + d2phirdt2;
394 }
395 
396 Real
398 {
399  // Note: second derivative of the ideal gas component wrt delta and tau is 0
400  // Derivative of the residual component wrt gamma
401  Real theta, Delta, Psi, dDelta_dd, dPsi_dd, dDelta_dt, dPsi_dt, d2Delta_ddt, d2Psi_ddt;
402  Real d2phirddt = 0.0;
403  for (std::size_t i = 0; i < _n1.size(); ++i)
404  d2phirddt += _n1[i] * _d1[i] * _t1[i] * MathUtils::pow(delta, _d1[i] - 1.0) *
405  std::pow(tau, _t1[i] - 1.0);
406 
407  for (std::size_t i = 0; i < _n2.size(); ++i)
408  d2phirddt += _n2[i] * std::exp(-MathUtils::pow(delta, _c2[i])) *
409  (MathUtils::pow(delta, _d2[i] - 1.0) * _t2[i] * std::pow(tau, _t2[i] - 1.0) *
410  (_d2[i] - _c2[i] * MathUtils::pow(delta, _c2[i])));
411 
412  for (std::size_t i = 0; i < _n3.size(); ++i)
413  d2phirddt += _n3[i] * MathUtils::pow(delta, _d3[i]) * MathUtils::pow(tau, _t3[i]) *
414  std::exp(-_alpha3[i] * Utility::pow<2>(delta - _eps3[i]) -
415  _beta3[i] * Utility::pow<2>(tau - _gamma3[i])) *
416  (_d3[i] / delta - 2.0 * _alpha3[i] * (delta - _eps3[i])) *
417  (_t3[i] / tau - 2.0 * _beta3[i] * (tau - _gamma3[i]));
418 
419  for (std::size_t i = 0; i < _n4.size(); ++i)
420  {
421  theta = 1.0 - tau + _A4[i] * std::pow(Utility::pow<2>(delta - 1.0), 1.0 / (2.0 * _beta4[i]));
422  Delta = Utility::pow<2>(theta) + _B4[i] * std::pow(Utility::pow<2>(delta - 1.0), _a4[i]);
423  Psi = std::exp(-_C4[i] * Utility::pow<2>(delta - 1.0) - _D4[i] * Utility::pow<2>(tau - 1.0));
424  dPsi_dd = -2.0 * _C4[i] * (delta - 1.0) * Psi;
425  dPsi_dt = -2.0 * _D4[i] * (tau - 1.0) * Psi;
426  d2Psi_ddt = 4.0 * _C4[i] * _D4[i] * (delta - 1.0) * (tau - 1.0) * Psi;
427  dDelta_dd = (delta - 1.0) *
428  (_A4[i] * theta * 2.0 / _beta4[i] *
429  std::pow(Utility::pow<2>(delta - 1.0), 1.0 / (2.0 * _beta4[i]) - 1.0) +
430  2.0 * _B4[i] * _a4[i] * std::pow(Utility::pow<2>(delta - 1.0), _a4[i] - 1.0));
431  dDelta_dt = -2.0 * theta * _b4[i] * std::pow(Delta, _b4[i] - 1.0);
432  d2Delta_ddt = -2.0 * _A4[i] * _b4[i] / _beta4[i] * std::pow(Delta, _b4[i] - 1.0) *
433  (delta - 1.0) *
434  std::pow(Utility::pow<2>(delta - 1.0), 1.0 / (2.0 * _beta4[i]) - 1.0) -
435  2.0 * theta * _b4[i] * (_b4[i] - 1.0) * std::pow(Delta, _b4[i] - 2.0) * dDelta_dd;
436 
437  d2phirddt += _n4[i] * (std::pow(Delta, _b4[i]) * (dPsi_dt + delta * d2Psi_ddt) +
438  delta * _b4[i] * std::pow(Delta, _b4[i] - 1.0) * dDelta_dd * dPsi_dt +
439  dDelta_dt * (Psi + delta * dPsi_dd) + d2Delta_ddt * delta * Psi);
440  }
441 
442  return d2phirddt;
443 }
444 
445 Real
447 {
448  // Check that the input parameters are within the region of validity
449  if (temperature < 216.0 || temperature > 1100.0 || density <= 0.0)
450  throw MooseException("Parameters out of range in " + name() + ": pressure()");
451 
452  Real pressure = 0.0;
453 
455  {
456  Real gas_density = saturatedVaporDensity(temperature);
457  Real liquid_density = saturatedLiquidDensity(temperature);
458 
459  if (density < gas_density || density > liquid_density)
461  else
463  }
464  else
466 
467  return pressure;
468 }
469 
470 Real
472 {
473  // Check that the input parameters are within the region of validity
474  if (temperature < 216.0 || temperature > 1100.0 || pressure <= 0.0)
475  throw MooseException("Parameters out of range in " + name() + ": rho_from_p_T()");
476 
477  // Also check that the pressure and temperature are not in the solid phase region
480  throw MooseException("Input pressure and temperature in " + name() +
481  ": rho_from_p_T() correspond to solid CO2 phase");
482 
483  Real density;
484  // Initial estimate of a bracketing interval for the density
485  Real lower_density = 100.0;
486  Real upper_density = 1000.0;
487 
488  // The density is found by finding the zero of the pressure calculated using the
489  // Span and Wagner EOS minus the input pressure
490  auto pressure_diff = [&pressure, &temperature, this](Real x)
491  { return p_from_rho_T(x, temperature) - pressure; };
492 
493  BrentsMethod::bracket(pressure_diff, lower_density, upper_density);
494  density = BrentsMethod::root(pressure_diff, lower_density, upper_density);
495 
496  return density;
497 }
498 
499 void
501  Real pressure, Real temperature, Real & rho, Real & drho_dp, Real & drho_dT) const
502 {
504 }
505 
506 Real
508 {
510  return mu_from_rho_T(rho, temperature);
511 }
512 
513 void
515  Real pressure, Real temperature, Real & mu, Real & dmu_dp, Real & dmu_dT) const
516 {
517  Real rho, drho_dp, drho_dT;
519 
520  Real dmu_drho;
521  mu_from_rho_T(rho, temperature, drho_dT, mu, dmu_drho, dmu_dT);
522  dmu_dp = dmu_drho * drho_dp;
523 }
524 
525 Real
527 {
528  // Check that the input parameters are within the region of validity
529  if (temperature < 216.0 || temperature > 1000.0 || density > 1400.0)
530  throw MooseException("Parameters out of range in " + name() + ": mu_from_rho_T()");
531 
532  Real Tstar = temperature / 251.196;
533 
534  // Viscosity in the zero-density limit
535  Real sum = 0.0;
536 
537  for (std::size_t i = 0; i < _mu_a.size(); ++i)
538  sum += _mu_a[i] * MathUtils::pow(std::log(Tstar), i);
539 
540  Real mu0 = 1.00697 * std::sqrt(temperature) / std::exp(sum);
541 
542  // Excess viscosity due to finite density
543  Real mue = _mu_d[0] * density + _mu_d[1] * Utility::pow<2>(density) +
544  _mu_d[2] * Utility::pow<6>(density) / Utility::pow<3>(Tstar) +
545  _mu_d[3] * Utility::pow<8>(density) + _mu_d[4] * Utility::pow<8>(density) / Tstar;
546 
547  return (mu0 + mue) * 1.0e-6; // convert to Pa.s
548 }
549 
550 void
552  Real temperature,
553  Real ddensity_dT,
554  Real & mu,
555  Real & dmu_drho,
556  Real & dmu_dT) const
557 {
558  // Check that the input parameters are within the region of validity
559  if (temperature < 216.0 || temperature > 1000.0 || density > 1400.0)
560  throw MooseException("Parameters out of range in " + name() + ": mu_drhoT()");
561 
562  Real Tstar = temperature / 251.196;
563  Real dTstar_dT = 1.0 / 251.196;
564 
565  // Viscosity in the zero-density limit. Note this is only a function of T.
566  // Start the sum at i = 1 so the derivative is defined
567  Real sum0 = _mu_a[0], dsum0_dTstar = 0.0;
568 
569  for (std::size_t i = 1; i < _mu_a.size(); ++i)
570  {
571  sum0 += _mu_a[i] * MathUtils::pow(std::log(Tstar), i);
572  dsum0_dTstar += i * _mu_a[i] * MathUtils::pow(std::log(Tstar), i - 1) / Tstar;
573  }
574 
575  Real mu0 = 1.00697 * std::sqrt(temperature) / std::exp(sum0);
576  Real dmu0_dT = (0.5 * 1.00697 / std::sqrt(temperature) -
577  1.00697 * std::sqrt(temperature) * dsum0_dTstar * dTstar_dT) /
578  std::exp(sum0);
579 
580  // Excess viscosity due to finite density
581  Real mue = _mu_d[0] * density + _mu_d[1] * Utility::pow<2>(density) +
582  _mu_d[2] * Utility::pow<6>(density) / Utility::pow<3>(Tstar) +
583  _mu_d[3] * Utility::pow<8>(density) + _mu_d[4] * Utility::pow<8>(density) / Tstar;
584 
585  Real dmue_drho = _mu_d[0] + 2.0 * _mu_d[1] * density +
586  6.0 * _mu_d[2] * Utility::pow<5>(density) / Utility::pow<3>(Tstar) +
587  8.0 * _mu_d[3] * Utility::pow<7>(density) +
588  8.0 * _mu_d[4] * Utility::pow<7>(density) / Tstar;
589 
590  Real dmue_dT = (-3.0 * _mu_d[2] * Utility::pow<6>(density) / Utility::pow<4>(Tstar) -
591  _mu_d[4] * Utility::pow<8>(density) / Tstar / Tstar) *
592  dTstar_dT;
593 
594  // Viscosity in Pa.s is
595  mu = (mu0 + mue) * 1.0e-6;
596  dmu_drho = dmue_drho * 1.0e-6;
597  dmu_dT = (dmu0_dT + dmue_dT) * 1.0e-6 + dmu_drho * ddensity_dT;
598 }
599 
600 void
601 CO2FluidProperties::rho_mu_from_p_T(Real pressure, Real temperature, Real & rho, Real & mu) const
602 {
605 }
606 
607 void
609  Real temperature,
610  Real & rho,
611  Real & drho_dp,
612  Real & drho_dT,
613  Real & mu,
614  Real & dmu_dp,
615  Real & dmu_dT) const
616 {
617  rho_from_p_T(pressure, temperature, rho, drho_dp, drho_dT);
618  Real dmu_drho;
619  mu_from_rho_T(rho, temperature, drho_dT, mu, dmu_drho, dmu_dT);
620  dmu_dp = dmu_drho * drho_dp;
621 }
622 
623 Real
625 {
626  // This correlation uses temperature in C
627  Real Tc = temperature - _T_c2k;
628  // The partial volume
629  Real V = 37.51 - 9.585e-2 * Tc + 8.74e-4 * Tc * Tc - 5.044e-7 * Tc * Tc * Tc;
630 
631  return 1.0e6 * _Mco2 / V;
632 }
633 
634 std::vector<Real>
636 {
637  return {-8.55445, 4.01195, 9.52345};
638 }
639 
640 Real
642 {
643  // Require density first
646 }
647 
648 void
650  Real pressure, Real temperature, Real & k, Real & dk_dp, Real & dk_dT) const
651 {
652  k = this->k_from_p_T(pressure, temperature);
653  // Calculate derivatives using finite differences. Note: this will be slow as
654  // multiple calculations of density are required
655  const Real eps = 1.0e-6;
656  const Real peps = pressure * eps;
657  const Real Teps = temperature * eps;
658 
659  dk_dp = (this->k_from_p_T(pressure + peps, temperature) - k) / peps;
660  dk_dT = (this->k_from_p_T(pressure, temperature + Teps) - k) / Teps;
661 }
662 
663 Real
665 {
666  // Check the temperature is in the range of validity (216.592 K <= T <= 1000 K)
667  if (temperature <= _triple_point_temperature || temperature >= 1000.0)
668  throw MooseException("Temperature " + Moose::stringify(temperature) +
669  "K out of range (200K, 1000K) in " + name() + ": k()");
670 
671  // Scaled variables
673  Real rhor = density / _critical_density;
674 
675  Real sum1 = 0.0;
676  for (std::size_t i = 0; i < _k_n1.size(); ++i)
677  sum1 += _k_n1[i] * std::pow(Tr, _k_g1[i]) * MathUtils::pow(rhor, _k_h1[i]);
678 
679  Real sum2 = 0.0;
680  for (std::size_t i = 0; i < _k_n2.size(); ++i)
681  sum2 += _k_n2[i] * std::pow(Tr, _k_g2[i]) * MathUtils::pow(rhor, _k_h2[i]);
682 
683  // Near-critical enhancement
684  Real alpha =
685  1.0 - _k_a[9] * std::acosh(1.0 + _k_a[10] * std::pow(Utility::pow<2>(1.0 - Tr), _k_a[11]));
686  Real lambdac =
687  rhor *
688  std::exp(-std::pow(rhor, _k_a[0]) / _k_a[0] - Utility::pow<2>(_k_a[1] * (Tr - 1.0)) -
689  Utility::pow<2>(_k_a[2] * (rhor - 1.0))) /
690  std::pow(std::pow(Utility::pow<2>(
691  1.0 - 1.0 / Tr +
692  _k_a[3] * std::pow(Utility::pow<2>(rhor - 1.0), 1.0 / (2.0 * _k_a[4]))),
693  _k_a[5]) +
694  std::pow(Utility::pow<2>(_k_a[6] * (rhor - alpha)), _k_a[7]),
695  _k_a[8]);
696 
697  return 4.81384 * (sum1 + std::exp(-5.0 * rhor * rhor) * sum2 + 0.775547504 * lambdac) / 1000.0;
698 }
virtual Real k_from_rho_T(Real density, Real temperature) const override
const std::array< Real, 7 > _k_n2
registerMooseObject("FluidPropertiesApp", CO2FluidProperties)
const std::array< Real, 3 > _D4
const std::array< Real, 7 > _t1
const Real eps
const std::array< unsigned int, 5 > _d3
CO2 fluid properties Most thermophysical properties taken from: Span and Wagner, "A New Equation of S...
Real sublimationPressure(Real temperature) const
Sublimation pressure.
Real saturatedLiquidDensity(Real temperature) const
Saturated liquid density of CO2 Valid for temperatures between the triple point temperature and criti...
const Real _critical_density
Critical density (kg/m^3)
virtual Real vaporPressure(Real temperature) const override
Vapor pressure.
const std::array< Real, 3 > _k_g1
Coefficients for the thermal conductivity.
const Real _critical_pressure
Critical pressure (Pa)
static const std::string density
Definition: NS.h:33
int delta(unsigned int i, unsigned int j)
Delta function, which returns zero if $i j$ and unity if $i=j$.
virtual std::string fluidName() const override
Fluid name.
static const std::string temperature
Definition: NS.h:59
const std::array< Real, 27 > _n2
const std::array< Real, 7 > _n1
Coefficients for the residual component of the Helmholtz free energy.
const std::array< Real, 3 > _C4
const std::array< Real, 5 > _theta0
virtual Real d2alpha_ddeltatau(Real delta, Real tau) const override
Second derivative of Helmholtz free energy wrt delta and tau.
virtual const std::string & name() const
CO2FluidProperties(const InputParameters &parameters)
const std::array< unsigned int, 7 > _k_h2
virtual Real rho_from_p_T(Real pressure, Real temperature) const override
Real saturatedVaporDensity(Real temperature) const
Saturated vapor density of CO2 Valid for temperatures between the triple point temperature and critic...
virtual Real triplePointTemperature() const override
Triple point temperature.
const std::array< unsigned int, 3 > _k_h1
const std::vector< double > x
const std::array< Real, 3 > _b4
static const std::string mu
Definition: NS.h:123
Real root(std::function< Real(Real)> const &f, Real x1, Real x2, Real tol=1.0e-12)
Finds the root of a function using Brent&#39;s method.
Definition: BrentsMethod.C:66
static InputParameters validParams()
virtual Real rho_from_p_T(Real pressure, Real temperature) const override
const std::array< Real, 5 > _mu_a
Coefficients for viscosity.
const std::array< Real, 3 > _a4
const std::array< Real, 5 > _n3
const std::array< unsigned int, 27 > _c2
const std::array< Real, 5 > _eps3
virtual Real d2alpha_dtau2(Real delta, Real tau) const override
Second derivative of Helmholtz free energy wrt tau.
static InputParameters validParams()
std::string stringify(const T &t)
const std::array< Real, 3 > _A4
const std::array< Real, 3 > _B4
virtual Real d2alpha_ddelta2(Real delta, Real tau) const override
Second derivative of Helmholtz free energy wrt delta.
virtual Real k_from_p_T(Real pressure, Real temperature) const override
const std::array< Real, 5 > _gamma3
const Real _triple_point_temperature
Triple point temperature (K)
const std::array< Real, 5 > _mu_d
const std::array< Real, 3 > _n4
virtual Real p_from_rho_T(Real rho, Real T) const
Pressure as a function of density and temperature.
virtual Real mu_from_p_T(Real pressure, Real temperature) const override
const std::array< Real, 5 > _alpha3
virtual Real dalpha_dtau(Real delta, Real tau) const override
Derivative of Helmholtz free energy wrt tau.
const Real _critical_temperature
Critical temperature (K)
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
const std::array< unsigned int, 5 > _t3
const std::array< Real, 3 > _beta4
virtual Real p_from_rho_T(Real density, Real temperature) const override
Pressure as a function of density and temperature.
static const std::string pressure
Definition: NS.h:56
virtual Real criticalDensity() const override
Critical density.
const std::array< Real, 12 > _k_a
void mooseError(Args &&... args) const
virtual std::vector< Real > henryCoefficients() const override
Henry&#39;s law coefficients for dissolution in water.
void addClassDescription(const std::string &doc_string)
const std::array< Real, 3 > _k_n1
virtual void rho_mu_from_p_T(Real pressure, Real temperature, Real &rho, Real &mu) const override
Combined methods.
virtual Real criticalPressure() const override
Critical pressure.
const Real _triple_point_pressure
Triple point pressure (Pa)
const std::array< Real, 5 > _a0
Coefficients for the ideal gas component of the Helmholtz free energy.
virtual Real mu_from_rho_T(Real density, Real temperature) const override
const std::array< Real, 27 > _t2
const std::array< Real, 7 > _k_g2
virtual Real criticalTemperature() const override
Critical temperature.
T pow(T x, int e)
const std::array< Real, 5 > _beta3
const std::array< unsigned int, 7 > _d1
Real partialDensity(Real temperature) const
Partial density of dissolved CO2 From Garcia, Density of aqueous solutions of CO2, LBNL-49023 (2001)
virtual Real dalpha_ddelta(Real delta, Real tau) const override
Derivative of Helmholtz free energy wrt delta.
Real meltingPressure(Real temperature) const
Melting pressure.
Base class equation of state for fluids that use a Helmholtz free energy alpha(delta, tau), where delta is a scaled density and tau is a scaled temperature.
MooseUnits pow(const MooseUnits &, int)
const Real _T_c2k
Conversion of temperature from Celsius to Kelvin.
static const std::string k
Definition: NS.h:130
virtual Real molarMass() const override
Molar mass [kg/mol].
virtual Real triplePointPressure() const override
Triple point pressure.
virtual Real alpha(Real delta, Real tau) const override
Helmholtz free energy.
const Real _Mco2
Molar mass of CO2 (kg/mol)
void bracket(std::function< Real(Real)> const &f, Real &x1, Real &x2)
Function to bracket a root of a given function.
Definition: BrentsMethod.C:17
const std::array< unsigned int, 27 > _d2