www.mooseframework.org
IdealRealGasMixtureFluidProperties.C
Go to the documentation of this file.
1 //* This file is part of the MOOSE framework
2 //* https://www.mooseframework.org
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 
12 #include "BrentsMethod.h"
13 #include <numeric>
14 
16 
17 template <>
18 InputParameters
20 {
21  InputParameters params = validParams<VaporMixtureFluidProperties>();
22  params += validParams<NaNInterface>();
23 
24  params.addClassDescription("Class for fluid properties of an arbitrary vapor mixture");
25 
26  params.addRequiredParam<UserObjectName>(
27  "fp_primary", "Name of fluid properties user object for primary vapor component");
28  params.addRequiredParam<std::vector<UserObjectName>>(
29  "fp_secondary", "Name of fluid properties user object(s) for secondary vapor component(s)");
30  params.addParam<Real>("_T_mix_max", 1300., "Maximum temperature of the mixture");
31 
32  // This is necessary because initialize() must be called before any interface
33  // can be used (which can occur as early as initialization of variables).
34  params.set<ExecFlagEnum>("execute_on") = EXEC_INITIAL;
35 
36  return params;
37 }
38 
40  const InputParameters & parameters)
41  : VaporMixtureFluidProperties(parameters),
42  NaNInterface(this),
43  _fp_secondary_names(getParam<std::vector<UserObjectName>>("fp_secondary")),
44  _n_secondary_vapors(_fp_secondary_names.size()),
45  _T_mix_max(getParam<Real>("_T_mix_max"))
46 {
47  _fp_primary = &getUserObject<SinglePhaseFluidProperties>("fp_primary");
48 
50  for (unsigned int i = 0; i < _n_secondary_vapors; i++)
51  _fp_secondary[i] = &getUserObjectByName<SinglePhaseFluidProperties>(_fp_secondary_names[i]);
52 }
53 
54 Real
55 IdealRealGasMixtureFluidProperties::p_from_v_e(Real v, Real e, const std::vector<Real> & x) const
56 {
57  Real p, T;
58  p_T_from_v_e(v, e, x, p, T);
59 
60  return p;
61 }
62 
63 void
65  Real e,
66  const std::vector<Real> & x,
67  Real & p,
68  Real & dp_dv,
69  Real & dp_de,
70  std::vector<Real> & dp_dx) const
71 {
72  Real T, dT_dv, dT_de;
73  std::vector<Real> dT_dx(_n_secondary_vapors);
74  p_T_from_v_e(v, e, x, p, dp_dv, dp_de, dp_dx, T, dT_dv, dT_de, dT_dx);
75 }
76 
77 Real
78 IdealRealGasMixtureFluidProperties::T_from_v_e(Real v, Real e, const std::vector<Real> & x) const
79 {
80  Real p, T;
81  p_T_from_v_e(v, e, x, p, T);
82 
83  return T;
84 }
85 
86 void
88  Real e,
89  const std::vector<Real> & x,
90  Real & T,
91  Real & dT_dv,
92  Real & dT_de,
93  std::vector<Real> & dT_dx) const
94 {
95  Real p, dp_dv, dp_de;
96  std::vector<Real> dp_dx(_n_secondary_vapors);
97  p_T_from_v_e(v, e, x, p, dp_dv, dp_de, dp_dx, T, dT_dv, dT_de, dT_dx);
98 }
99 
100 Real
101 IdealRealGasMixtureFluidProperties::c_from_v_e(Real v, Real e, const std::vector<Real> & x) const
102 {
103  Real p, T;
104  p_T_from_v_e(v, e, x, p, T);
105  return c_from_T_v(T, v, x);
106 }
107 
108 void
110  Real e,
111  const std::vector<Real> & x,
112  Real & c,
113  Real & dc_dv,
114  Real & dc_de,
115  std::vector<Real> & dc_dx) const
116 {
117  Real p, T;
118  p_T_from_v_e(v, e, x, p, T);
119 
120  // sound of speed and derivatives
121  Real dc_dT_v, dc_dv_T;
122  std::vector<Real> dc_dx_Tv;
123  c_from_T_v(T, v, x, c, dc_dT_v, dc_dv_T, dc_dx_Tv);
124 
125  // internal energy and derivatives
126  Real e_unused, de_dT_v, de_dv_T;
127  std::vector<Real> de_dx_Tv;
128  e_from_T_v(T, v, x, e_unused, de_dT_v, de_dv_T, de_dx_Tv);
129 
130  // Compute derivatives using the following rules:
131  dc_dv = dc_dv_T - dc_dT_v * de_dv_T / de_dT_v;
132  dc_de = dc_dT_v / de_dT_v;
133 
134  // Derivatives with respect to mass fractions:
135  for (unsigned int i = 0; i < _n_secondary_vapors; i++)
136  {
137  dc_dx[i] = dc_dx_Tv[i] - dc_dT_v * de_dx_Tv[i] / de_dT_v;
138  }
139 }
140 
141 Real
142 IdealRealGasMixtureFluidProperties::rho_from_p_T(Real p, Real T, const std::vector<Real> & x) const
143 {
144  return 1.0 / v_from_p_T(p, T, x);
145 }
146 
147 void
149  Real T,
150  const std::vector<Real> & x,
151  Real & rho,
152  Real & drho_dp,
153  Real & drho_dT,
154  std::vector<Real> & drho_dx) const
155 {
156  Real v, dv_dp, dv_dT;
157  std::vector<Real> dv_dx;
158  v_from_p_T(p, T, x, v, dv_dp, dv_dT, dv_dx);
159 
160  rho = 1.0 / v;
161  const Real drho_dv = -1.0 / (v * v);
162  drho_dp = drho_dv * dv_dp;
163  drho_dT = drho_dv * dv_dT;
164  drho_dx.resize(_n_secondary_vapors);
165  for (unsigned int i = 0; i < _n_secondary_vapors; i++)
166  drho_dx[i] = drho_dv * dv_dx[i];
167 }
168 
169 Real
170 IdealRealGasMixtureFluidProperties::v_from_p_T(Real p, Real T, const std::vector<Real> & x) const
171 {
172  const Real x_primary = primaryMassFraction(x);
173  Real M_primary = _fp_primary->molarMass();
174 
175  Real sum = x_primary / M_primary;
176  for (unsigned int i = 0; i < _n_secondary_vapors; i++)
177  sum += x[i] / _fp_secondary[i]->molarMass();
178  Real M_star = 1. / sum;
179  Real v_ideal = R_molar * T / (M_star * p);
180 
181  // check range of validity for primary (condensable) component
182  static const Real Tc = _fp_primary->criticalTemperature();
183  static const Real vc = 1. / _fp_primary->criticalDensity();
184  Real v_spndl, e_spndl;
185  if (T < Tc)
186  _fp_primary->v_e_spndl_from_T(T, v_spndl, e_spndl);
187  else
188  v_spndl = vc;
189 
190  Real lower_spec_volume = v_spndl * x_primary;
191  Real upper_spec_volume = v_ideal; // p*v/(RT) <= 1
192 
193  // Initial estimate of a bracketing interval for the temperature
194  Real p_max = p_from_T_v(T, lower_spec_volume, x);
195  if (p > p_max || upper_spec_volume < lower_spec_volume)
196  return getNaN();
197 
198  // Use BrentsMethod to find temperature
199  auto pressure_diff = [&T, &p, &x, this](Real v) { return this->p_from_T_v(T, v, x) - p; };
200 
201  BrentsMethod::bracket(pressure_diff, lower_spec_volume, upper_spec_volume);
202  Real v = BrentsMethod::root(pressure_diff, lower_spec_volume, upper_spec_volume);
203 
204  return v;
205 }
206 
207 void
209  Real T,
210  const std::vector<Real> & x,
211  Real & v,
212  Real & dv_dp,
213  Real & dv_dT,
214  std::vector<Real> & dv_dx) const
215 {
216  Real p_unused, dp_dT, dp_dv;
217  std::vector<Real> dp_dx;
218  dp_dx.resize(_n_secondary_vapors);
219 
220  v = v_from_p_T(p, T, x);
221  p_from_T_v(T, v, x, p_unused, dp_dT, dp_dv, dp_dx);
222 
223  dv_dp = 1. / dp_dv;
224  dv_dT = -dp_dT / dp_dv;
225 
226  dv_dx.resize(_n_secondary_vapors);
227  for (unsigned int i = 0; i < _n_secondary_vapors; i++)
228  dv_dx[i] = -dp_dx[i] / dp_dv;
229 }
230 
231 Real
232 IdealRealGasMixtureFluidProperties::e_from_p_T(Real p, Real T, const std::vector<Real> & x) const
233 {
234  Real v = v_from_p_T(p, T, x);
235  return e_from_T_v(T, v, x);
236 }
237 
238 void
240  Real T,
241  const std::vector<Real> & x,
242  Real & e,
243  Real & de_dp,
244  Real & de_dT,
245  std::vector<Real> & de_dx) const
246 {
247  Real v, de_dT_v, de_dv_T, p_unused, dp_dT_v, dp_dv_T;
248  std::vector<Real> de_dx_Tv, dp_dx_Tv;
249  de_dx_Tv.resize(_n_secondary_vapors);
250  dp_dx_Tv.resize(_n_secondary_vapors);
251 
252  v = v_from_p_T(p, T, x);
253  e_from_T_v(T, v, x, e, de_dT_v, de_dv_T, de_dx_Tv);
254  p_from_T_v(T, v, x, p_unused, dp_dT_v, dp_dv_T, dp_dx_Tv);
255 
256  de_dp = de_dv_T / dp_dv_T;
257  de_dT = de_dT_v - de_dv_T * dp_dT_v / dp_dv_T;
258 
259  de_dx.resize(_n_secondary_vapors);
260  for (unsigned int i = 0; i < _n_secondary_vapors; i++)
261  de_dx[i] = -(de_dv_T - de_dx_Tv[i] * dp_dv_T / dp_dx_Tv[i]) * dp_dx_Tv[i] / dp_dv_T;
262 }
263 
264 Real
265 IdealRealGasMixtureFluidProperties::c_from_p_T(Real p, Real T, const std::vector<Real> & x) const
266 {
267  Real v;
268  Real p_unused, dp_dT, dp_dv;
269  Real s, ds_dT, ds_dv;
270 
271  v = v_from_p_T(p, T, x);
272  p_from_T_v(T, v, x, p_unused, dp_dT, dp_dv);
273  s_from_T_v(T, v, x, s, ds_dT, ds_dv);
274 
275  Real dp_dv_s = dp_dv - dp_dT * ds_dv / ds_dT;
276 
277  if (dp_dv_s >= 0)
278  mooseWarning(name(), ":c_from_p_T(), dp_dv_s = ", dp_dv_s, ". Should be negative.");
279  return v * std::sqrt(-dp_dv_s);
280 }
281 
282 void
284  Real T,
285  const std::vector<Real> & x,
286  Real & c,
287  Real & dc_dp,
288  Real & dc_dT,
289  std::vector<Real> & dc_dx) const
290 {
291  Real p_perturbed, T_perturbed, c_perturbed;
292 
293  c = c_from_p_T(p, T, x);
294  // For derived properties, we would need higher order derivatives;
295  // therefore, numerical derivatives are used here
296  Real dp = p * 1.e-6;
297  p_perturbed = p + dp;
298  c_perturbed = c_from_p_T(p_perturbed, T, x);
299  dc_dp = (c_perturbed - c) / (dp);
300 
301  Real dT = 1.e-6;
302  T_perturbed = T + dT;
303  c_perturbed = c_from_p_T(p, T_perturbed, x);
304  dc_dT = (c_perturbed - c) / (dT);
305 
306  dc_dx.resize(_n_secondary_vapors);
307  for (unsigned int i = 0; i < _n_secondary_vapors; i++)
308  {
309  Real c_perturbed;
310  std::vector<Real> x_perturbed(x);
311  Real dx_i = 1e-6;
312  for (unsigned int j = 0; j < _n_secondary_vapors; j++)
313  {
314  if (j != i)
315  x_perturbed[j] =
316  x[j] * (1.0 - (x[i] + dx_i)) / (1.0 - x[i]); // recalculate new mass fractions
317  }
318  x_perturbed[i] += dx_i;
319  c_perturbed = c_from_p_T(p, T, x_perturbed);
320  dc_dx[i] = ((c_perturbed - c) / dx_i);
321  }
322 }
323 
324 Real
325 IdealRealGasMixtureFluidProperties::cp_from_p_T(Real p, Real T, const std::vector<Real> & x) const
326 {
327  Real p_unused, dp_dT, dp_dv;
328  Real h, dh_dT, dh_dv;
329 
330  Real v = v_from_p_T(p, T, x);
331  p_from_T_v(T, v, x, p_unused, dp_dT, dp_dv);
332 
333  const Real x_primary = primaryMassFraction(x);
334 
335  _fp_primary->h_from_T_v(T, v / x_primary, h, dh_dT, dh_dv);
336  Real cp = x_primary * (dh_dT - dh_dv * dp_dT / dp_dv);
337 
338  for (unsigned int i = 0; i < _n_secondary_vapors; i++)
339  {
340  _fp_secondary[i]->h_from_T_v(T, v / x[i], h, dh_dT, dh_dv);
341  cp += x[i] * (dh_dT - dh_dv * dp_dT / dp_dv);
342  }
343 
344  return cp;
345 }
346 
347 Real
348 IdealRealGasMixtureFluidProperties::cv_from_p_T(Real p, Real T, const std::vector<Real> & x) const
349 {
350  Real v = v_from_p_T(p, T, x);
351 
352  const Real x_primary = primaryMassFraction(x);
353  Real cv = x_primary * _fp_primary->cv_from_T_v(T, v / x_primary);
354 
355  for (unsigned int i = 0; i < _n_secondary_vapors; i++)
356  cv += x[i] * _fp_secondary[i]->cv_from_T_v(T, v / x[i]);
357 
358  return cv;
359 }
360 
361 Real
362 IdealRealGasMixtureFluidProperties::mu_from_p_T(Real p, Real T, const std::vector<Real> & x) const
363 {
364  Real v = v_from_p_T(p, T, x);
365 
366  const Real x_primary = primaryMassFraction(x);
367  Real M_primary = _fp_primary->molarMass();
368 
369  Real sum = x_primary / M_primary;
370  for (unsigned int i = 0; i < _n_secondary_vapors; i++)
371  sum += x[i] / _fp_secondary[i]->molarMass();
372  Real M_star = 1. / sum;
373 
374  Real vp = v / x_primary;
375  Real ep = _fp_primary->e_from_T_v(T, vp);
376  Real mu = x_primary * M_star / M_primary * _fp_primary->mu_from_v_e(vp, ep);
377 
378  for (unsigned int i = 0; i < _n_secondary_vapors; i++)
379  {
380  Real vi = v / x[i];
381  Real ei = _fp_secondary[i]->e_from_T_v(T, vp);
382  Real Mi = _fp_secondary[i]->molarMass();
383  mu += x[i] * M_star / Mi * _fp_secondary[i]->mu_from_v_e(vi, ei);
384  }
385 
386  return mu;
387 }
388 
389 Real
390 IdealRealGasMixtureFluidProperties::k_from_p_T(Real p, Real T, const std::vector<Real> & x) const
391 {
392  Real v = v_from_p_T(p, T, x);
393 
394  const Real x_primary = primaryMassFraction(x);
395  Real M_primary = _fp_primary->molarMass();
396 
397  Real sum = x_primary / M_primary;
398  for (unsigned int i = 0; i < _n_secondary_vapors; i++)
399  sum += x[i] / _fp_secondary[i]->molarMass();
400  Real M_star = 1. / sum;
401 
402  Real vp = v / x_primary;
403  Real ep = _fp_primary->e_from_T_v(T, vp);
404  Real k = x_primary * M_star / M_primary * _fp_primary->k_from_v_e(vp, ep);
405 
406  for (unsigned int i = 0; i < _n_secondary_vapors; i++)
407  {
408  Real vi = v / x[i];
409  Real ei = _fp_secondary[i]->e_from_T_v(T, vp);
410  Real Mi = _fp_secondary[i]->molarMass();
411  k += x[i] * M_star / Mi * _fp_secondary[i]->k_from_v_e(vi, ei);
412  }
413 
414  return k;
415 }
416 
417 Real
419  Real rho,
420  const std::vector<Real> & x) const
421 {
422  Real v = 1. / rho;
423  Real T = T_from_p_v(p, v, x);
424 
425  return e_from_T_v(T, v, x);
426 }
427 
428 void
430  Real rho,
431  const std::vector<Real> & x,
432  Real & e,
433  Real & de_dp,
434  Real & de_drho,
435  std::vector<Real> & de_dx) const
436 {
437  Real v = 1. / rho;
438  Real T = T_from_p_v(p, v, x);
439  Real p_, dp_dT, dp_dv, de_dT, de_dv;
440  std::vector<Real> dp_dx_Tv;
441  std::vector<Real> de_dx_Tv;
442 
443  p_from_T_v(T, v, x, p_, dp_dT, dp_dv, dp_dx_Tv);
444  e_from_T_v(T, v, x, e, de_dT, de_dv, de_dx_Tv);
445 
446  de_dp = de_dT / dp_dT;
447  de_drho = (-v * v) * (de_dv - de_dT * dp_dv / dp_dT);
448 
449  // Derivatives with respect to mass fractions:
450  for (unsigned int i = 0; i < _n_secondary_vapors; i++)
451  {
452  de_dx[i] = de_dx_Tv[i] - de_dT * dp_dx_Tv[i] / dp_dT;
453  }
454 }
455 
456 void
458  Real v, Real e, const std::vector<Real> & x, Real & p, Real & T) const
459 {
460  Real v_primary = v / primaryMassFraction(x);
461  static const Real vc = 1. / _fp_primary->criticalDensity();
462  static const Real ec = _fp_primary->criticalInternalEnergy();
463 
464  // Initial estimate of a bracketing interval for the temperature
465  Real lower_temperature, upper_temperature;
466  if (v_primary > vc)
467  {
468  Real e_sat_primary = _fp_primary->e_spndl_from_v(v_primary);
469  lower_temperature = _fp_primary->T_from_v_e(v_primary, e_sat_primary);
470  }
471  else
472  lower_temperature = _fp_primary->T_from_v_e(v_primary, ec);
473 
474  upper_temperature = _T_mix_max;
475 
476  // Use BrentsMethod to find temperature
477  auto energy_diff = [&v, &e, &x, this](Real T) { return this->e_from_T_v(T, v, x) - e; };
478 
479  BrentsMethod::bracket(energy_diff, lower_temperature, upper_temperature);
480  T = BrentsMethod::root(energy_diff, lower_temperature, upper_temperature);
481 
482  p = p_from_T_v(T, v, x);
483 }
484 
485 void
487  Real e,
488  const std::vector<Real> & x,
489  Real & p,
490  Real & dp_dv,
491  Real & dp_de,
492  std::vector<Real> & dp_dx,
493  Real & T,
494  Real & dT_dv,
495  Real & dT_de,
496  std::vector<Real> & dT_dx) const
497 {
498  p_T_from_v_e(v, e, x, p, T);
499 
500  // pressure and derivatives
501  Real p_unused, dp_dT_v, dp_dv_T;
502  std::vector<Real> dp_dx_Tv;
503  p_from_T_v(T, v, x, p_unused, dp_dT_v, dp_dv_T, dp_dx_Tv);
504 
505  // internal energy and derivatives
506  Real e_unused, de_dT_v, de_dv_T;
507  std::vector<Real> de_dx_Tv;
508  e_from_T_v(T, v, x, e_unused, de_dT_v, de_dv_T, de_dx_Tv);
509 
510  // Compute derivatives using the following rules:
511  dp_dv = dp_dv_T - dp_dT_v * de_dv_T / de_dT_v;
512  dp_de = dp_dT_v / de_dT_v;
513  dT_dv = -de_dv_T / de_dT_v;
514  dT_de = 1. / de_dT_v;
515 
516  // Derivatives with respect to mass fractions:
517  for (unsigned int i = 0; i < _n_secondary_vapors; i++)
518  {
519  dT_dx[i] = -de_dx_Tv[i] / de_dT_v;
520  dp_dx[i] = dp_dx_Tv[i] + dp_dT_v * dT_dx[i];
521  }
522 }
523 
524 Real
525 IdealRealGasMixtureFluidProperties::T_from_p_v(Real p, Real v, const std::vector<Real> & x) const
526 {
527  Real v_primary = v / primaryMassFraction(x);
528  static const Real vc = 1. / _fp_primary->criticalDensity();
529  static const Real ec = _fp_primary->criticalInternalEnergy();
530 
531  // Initial estimate of a bracketing interval for the temperature
532  Real lower_temperature, upper_temperature;
533  if (v_primary > vc)
534  {
535  Real e_sat_primary = _fp_primary->e_spndl_from_v(v_primary);
536  lower_temperature = _fp_primary->T_from_v_e(v_primary, e_sat_primary);
537  }
538  else
539  lower_temperature = _fp_primary->T_from_v_e(v_primary, ec);
540 
541  upper_temperature = _T_mix_max;
542 
543  // Use BrentsMethod to find temperature
544  auto pressure_diff = [&p, &v, &x, this](Real T) { return this->p_from_T_v(T, v, x) - p; };
545 
546  BrentsMethod::bracket(pressure_diff, lower_temperature, upper_temperature);
547  Real T = BrentsMethod::root(pressure_diff, lower_temperature, upper_temperature);
548 
549  return T;
550 }
551 
552 void
554  Real v,
555  const std::vector<Real> & x,
556  Real & T,
557  Real & dT_dp,
558  Real & dT_dv,
559  std::vector<Real> & dT_dx) const
560 {
561  T = T_from_p_v(p, v, x);
562 
563  // pressure and derivatives
564  Real p_unused, dp_dT_v, dp_dv_T;
565  std::vector<Real> dp_dx_Tv;
566  p_from_T_v(T, v, x, p_unused, dp_dT_v, dp_dv_T, dp_dx_Tv);
567 
568  // Compute derivatives using the following rules:
569  dT_dp = 1. / dp_dT_v;
570  dT_dv = -dp_dv_T / dp_dT_v;
571 
572  // Derivatives with respect to mass fractions:
573  for (unsigned int i = 0; i < _n_secondary_vapors; i++)
574  {
575  dT_dx[i] = -dp_dx_Tv[i] / dp_dT_v;
576  }
577 }
578 
579 Real
580 IdealRealGasMixtureFluidProperties::p_from_T_v(Real T, Real v, const std::vector<Real> & x) const
581 {
582  const Real x_primary = primaryMassFraction(x);
583  Real p = _fp_primary->p_from_T_v(T, v / x_primary);
584 
585  for (unsigned int i = 0; i < _n_secondary_vapors; i++)
586  p += _fp_secondary[i]->p_from_T_v(T, v / x[i]);
587 
588  return p;
589 }
590 
591 void
593  Real T, Real v, const std::vector<Real> & x, Real & p, Real & dp_dT, Real & dp_dv) const
594 {
595  Real p_primary, dp_dT_primary, dp_dv_primary;
596  Real p_sec, dp_dT_sec, dp_dv_sec;
597 
598  const Real x_primary = primaryMassFraction(x);
599 
600  _fp_primary->p_from_T_v(T, v / x_primary, p_primary, dp_dT_primary, dp_dv_primary);
601  p = p_primary;
602  dp_dT = dp_dT_primary;
603  dp_dv = dp_dv_primary / x_primary;
604 
605  for (unsigned int i = 0; i < _n_secondary_vapors; i++)
606  {
607  _fp_secondary[i]->p_from_T_v(T, v / x[i], p_sec, dp_dT_sec, dp_dv_sec);
608 
609  p += p_sec;
610  dp_dT += dp_dT_sec;
611  dp_dv += dp_dv_sec / x[i];
612  }
613 }
614 
615 void
617  Real v,
618  const std::vector<Real> & x,
619  Real & p,
620  Real & dp_dT,
621  Real & dp_dv,
622  std::vector<Real> & dp_dx) const
623 {
624  Real p_primary, dp_dT_primary, dp_dv_primary, dp_dx_primary, dxi_dx_primary;
625  Real p_sec, dp_dT_sec, dxj_dxi;
626  std::vector<Real> dp_dv_sec;
627 
628  const Real x_primary = primaryMassFraction(x);
629  dp_dx.resize(_n_secondary_vapors);
630  dp_dv_sec.resize(_n_secondary_vapors);
631 
632  _fp_primary->p_from_T_v(T, v / x_primary, p_primary, dp_dT_primary, dp_dv_primary);
633  p = p_primary;
634  dp_dT = dp_dT_primary;
635  dp_dv = dp_dv_primary / x_primary;
636  dp_dx_primary = -dp_dv_primary * v / (x_primary * x_primary);
637 
638  // get the partial pressures and their derivatives first
639  for (unsigned int i = 0; i < _n_secondary_vapors; i++)
640  {
641  _fp_secondary[i]->p_from_T_v(T, v / x[i], p_sec, dp_dT_sec, dp_dv_sec[i]);
642 
643  p += p_sec;
644  dp_dT += dp_dT_sec;
645  dp_dv += dp_dv_sec[i] / x[i];
646  dxi_dx_primary = -x[i] / (1. - x_primary);
647  dp_dx_primary += -dp_dv_sec[i] * v / (x[i] * x[i]) * dxi_dx_primary;
648  }
649 
650  // get the composition dependent derivatives of the secondary vapors
651  for (unsigned int i = 0; i < _n_secondary_vapors; i++)
652  {
653  dp_dx[i] = -dp_dv_sec[i] * v / (x[i] * x[i]);
654  for (unsigned int j = 0; j < _n_secondary_vapors; j++)
655  {
656  if (j == i)
657  continue;
658  dxj_dxi = -x[j] / (1. - x[i]);
659  dp_dx[i] += -dp_dv_sec[j] * v / (x[j] * x[j]) * dxj_dxi;
660  }
661  dp_dx[i] += -dp_dv_primary * v / (x_primary * x_primary) * (-x_primary / (1. - x[i]));
662  }
663 }
664 
665 Real
666 IdealRealGasMixtureFluidProperties::e_from_T_v(Real T, Real v, const std::vector<Real> & x) const
667 {
668  const Real x_primary = primaryMassFraction(x);
669  Real e = x_primary * _fp_primary->e_from_T_v(T, v / x_primary);
670 
671  for (unsigned int i = 0; i < _n_secondary_vapors; i++)
672  e += x[i] * _fp_secondary[i]->e_from_T_v(T, v / x[i]);
673 
674  return e;
675 }
676 
677 void
679  Real v,
680  const std::vector<Real> & x,
681  Real & e,
682  Real & de_dT,
683  Real & de_dv,
684  std::vector<Real> & de_dx) const
685 {
686  Real e_primary, de_dT_primary, de_dv_primary, de_dx_primary, dxi_dx_primary;
687  Real de_dT_sec, dxj_dxi, dx_primary_dxi;
688  std::vector<Real> e_sec, de_dv_sec;
689 
690  const Real x_primary = primaryMassFraction(x);
691  de_dx.resize(_n_secondary_vapors);
692  e_sec.resize(_n_secondary_vapors);
693  de_dv_sec.resize(_n_secondary_vapors);
694 
695  _fp_primary->e_from_T_v(T, v / x_primary, e_primary, de_dT_primary, de_dv_primary);
696  e = x_primary * e_primary;
697  de_dT = x_primary * de_dT_primary;
698  de_dv = de_dv_primary;
699  de_dx_primary = e_primary - x_primary * de_dv_primary * v / (x_primary * x_primary);
700 
701  // get the partial pressures and their derivatives first
702  for (unsigned int i = 0; i < _n_secondary_vapors; i++)
703  {
704  _fp_secondary[i]->e_from_T_v(T, v / x[i], e_sec[i], de_dT_sec, de_dv_sec[i]);
705 
706  e += x[i] * e_sec[i];
707  de_dT += x[i] * de_dT_sec;
708  de_dv += de_dv_sec[i];
709  dxi_dx_primary = -x[i] / (1. - x_primary);
710  de_dx_primary +=
711  dxi_dx_primary * e_sec[i] - x[i] * de_dv_sec[i] * v / (x[i] * x[i]) * dxi_dx_primary;
712  }
713 
714  // get the composition dependent derivatives of the secondary vapors
715  for (unsigned int i = 0; i < _n_secondary_vapors; i++)
716  {
717  de_dx[i] = e_sec[i] - x[i] * de_dv_sec[i] * v / (x[i] * x[i]);
718  for (unsigned int j = 0; j < _n_secondary_vapors; j++)
719  {
720  if (j == i)
721  continue;
722  dxj_dxi = -x[j] / (1. - x[i]);
723  de_dx[i] += dxj_dxi * e_sec[j] - x[j] * de_dv_sec[j] * v / (x[j] * x[j]) * dxj_dxi;
724  }
725  dx_primary_dxi = -x_primary / (1. - x[i]);
726  de_dx[i] += dx_primary_dxi * e_primary -
727  x_primary * de_dv_primary * v / (x_primary * x_primary) * dx_primary_dxi;
728  }
729 }
730 
731 void
733  Real T, Real v, const std::vector<Real> & x, Real & s, Real & ds_dT, Real & ds_dv) const
734 {
735  Real s_primary, ds_dT_primary, ds_dv_primary;
736  Real s_sec, ds_dT_sec, ds_dv_sec;
737 
738  const Real x_primary = primaryMassFraction(x);
739 
740  _fp_primary->s_from_T_v(T, v / x_primary, s_primary, ds_dT_primary, ds_dv_primary);
741  s = x_primary * s_primary;
742  ds_dT = x_primary * ds_dT_primary;
743  ds_dv = ds_dv_primary;
744 
745  for (unsigned int i = 0; i < _n_secondary_vapors; i++)
746  {
747  _fp_secondary[i]->s_from_T_v(T, v / x[i], s_sec, ds_dT_sec, ds_dv_sec);
748 
749  s += x[i] * s_sec;
750  ds_dT += x[i] * ds_dT_sec;
751  ds_dv += ds_dv_sec;
752  }
753 }
754 
755 Real
756 IdealRealGasMixtureFluidProperties::c_from_T_v(Real T, Real v, const std::vector<Real> & x) const
757 {
758  Real p, dp_dT, dp_dv;
759  Real s, ds_dT, ds_dv;
760 
761  p_from_T_v(T, v, x, p, dp_dT, dp_dv);
762  s_from_T_v(T, v, x, s, ds_dT, ds_dv);
763 
764  Real dp_dv_s = dp_dv - dp_dT * ds_dv / ds_dT;
765 
766  if (dp_dv_s >= 0)
767  mooseWarning(name(), ":c_from_T_v(), dp_dv_s = ", dp_dv_s, ". Should be negative.");
768  return v * std::sqrt(-dp_dv_s);
769 }
770 
771 void
773  Real v,
774  const std::vector<Real> & x,
775  Real & c,
776  Real & dc_dT,
777  Real & dc_dv,
778  std::vector<Real> & dc_dx) const
779 {
780  Real T_perturbed, v_perturbed, c_perturbed;
781 
782  c = c_from_T_v(T, v, x);
783  // For derived properties, we would need higher order derivatives;
784  // therefore, numerical derivatives are used here.
785  Real dT = 1.e-6;
786  T_perturbed = T + dT;
787  c_perturbed = c_from_T_v(T_perturbed, v, x);
788  dc_dT = (c_perturbed - c) / (dT);
789 
790  Real dv = v * 1.e-6;
791  v_perturbed = v + dv;
792  c_perturbed = c_from_T_v(T, v_perturbed, x);
793  dc_dv = (c_perturbed - c) / (dv);
794 
795  dc_dx.resize(_n_secondary_vapors);
796  for (unsigned int i = 0; i < _n_secondary_vapors; i++)
797  {
798  Real c_perturbed;
799  std::vector<Real> x_perturbed(x);
800  Real dx_i = 1e-6;
801  for (unsigned int j = 0; j < _n_secondary_vapors; j++)
802  {
803  if (j != i)
804  x_perturbed[j] =
805  x[j] * (1.0 - (x[i] + dx_i)) / (1.0 - x[i]); // recalculate new mass fractions
806  }
807  x_perturbed[i] += dx_i;
808  c_perturbed = c_from_T_v(T, v, x_perturbed);
809  dc_dx[i] = ((c_perturbed - c) / dx_i);
810  }
811 }
812 
813 Real
814 IdealRealGasMixtureFluidProperties::cp_from_T_v(Real T, Real v, const std::vector<Real> & x) const
815 {
816  Real p, dp_dT, dp_dv;
817  Real h, dh_dT, dh_dv;
818 
819  p_from_T_v(T, v, x, p, dp_dT, dp_dv);
820 
821  const Real x_primary = primaryMassFraction(x);
822 
823  _fp_primary->h_from_T_v(T, v / x_primary, h, dh_dT, dh_dv);
824  Real cp = x_primary * (dh_dT - dh_dv * dp_dT / dp_dv);
825 
826  for (unsigned int i = 0; i < _n_secondary_vapors; i++)
827  {
828  _fp_secondary[i]->h_from_T_v(T, v / x[i], h, dh_dT, dh_dv);
829  cp += x[i] * (dh_dT - dh_dv * dp_dT / dp_dv);
830  }
831 
832  return cp;
833 }
834 
835 Real
836 IdealRealGasMixtureFluidProperties::cv_from_T_v(Real T, Real v, const std::vector<Real> & x) const
837 {
838  const Real x_primary = primaryMassFraction(x);
839  Real cv = x_primary * _fp_primary->cv_from_T_v(T, v / x_primary);
840 
841  for (unsigned int i = 0; i < _n_secondary_vapors; i++)
842  cv += x[i] * _fp_secondary[i]->cv_from_T_v(T, v / x[i]);
843 
844  return cv;
845 }
846 
847 Real
848 IdealRealGasMixtureFluidProperties::mu_from_T_v(Real T, Real v, const std::vector<Real> & x) const
849 {
850  const Real x_primary = primaryMassFraction(x);
851  Real M_primary = _fp_primary->molarMass();
852 
853  Real sum = x_primary / M_primary;
854  for (unsigned int i = 0; i < _n_secondary_vapors; i++)
855  sum += x[i] / _fp_secondary[i]->molarMass();
856  Real M_star = 1. / sum;
857 
858  Real vp = v / x_primary;
859  Real ep = _fp_primary->e_from_T_v(T, vp);
860  Real mu = x_primary * M_star / M_primary * _fp_primary->mu_from_v_e(vp, ep);
861 
862  for (unsigned int i = 0; i < _n_secondary_vapors; i++)
863  {
864  Real vi = v / x[i];
865  Real ei = _fp_secondary[i]->e_from_T_v(T, vp);
866  Real Mi = _fp_secondary[i]->molarMass();
867  mu += x[i] * M_star / Mi * _fp_secondary[i]->mu_from_v_e(vi, ei);
868  }
869 
870  return mu;
871 }
872 
873 Real
874 IdealRealGasMixtureFluidProperties::k_from_T_v(Real T, Real v, const std::vector<Real> & x) const
875 {
876  const Real x_primary = primaryMassFraction(x);
877  Real M_primary = _fp_primary->molarMass();
878 
879  Real sum = x_primary / M_primary;
880  for (unsigned int i = 0; i < _n_secondary_vapors; i++)
881  sum += x[i] / _fp_secondary[i]->molarMass();
882  Real M_star = 1. / sum;
883 
884  Real vp = v / x_primary;
885  Real ep = _fp_primary->e_from_T_v(T, vp);
886  Real k = x_primary * M_star / M_primary * _fp_primary->k_from_v_e(vp, ep);
887 
888  for (unsigned int i = 0; i < _n_secondary_vapors; i++)
889  {
890  Real vi = v / x[i];
891  Real ei = _fp_secondary[i]->e_from_T_v(T, vp);
892  Real Mi = _fp_secondary[i]->molarMass();
893  k += x[i] * M_star / Mi * _fp_secondary[i]->k_from_v_e(vi, ei);
894  }
895 
896  return k;
897 }
898 
899 Real
901  Real T,
902  const std::vector<Real> & x) const
903 {
904  Real T_c = _fp_primary->criticalTemperature();
905  Real xs;
906  if (T > T_c)
907  // return 1. to indicate that no water would condense for
908  // given (p,T)
909  xs = 1.;
910  else
911  {
912  Real pp_sat = _fp_primary->pp_sat_from_p_T(p, T);
913  if (pp_sat < 0.)
914  {
915  // return 1. to indicate that no water would condense for
916  // given (p,T)
917  xs = 1.;
918  return xs;
919  }
920  Real v_primary = _fp_primary->v_from_p_T(pp_sat, T);
921  Real pp_sat_secondary = p - pp_sat;
922 
923  Real v_secondary;
924  if (_n_secondary_vapors == 1)
925  v_secondary = _fp_secondary[0]->v_from_p_T(pp_sat_secondary, T);
926  else
927  {
928  std::vector<Real> x_sec(_n_secondary_vapors);
929  const Real x_primary = primaryMassFraction(x);
930  Real sum = 0.;
931  for (unsigned int i = 0; i < _n_secondary_vapors; i++)
932  {
933  x_sec[i] = x[i] / (1. - x_primary);
934  sum += x_sec[i] / _fp_secondary[i]->molarMass();
935  }
936  Real M_star = 1. / sum;
937  v_secondary = R_molar * T / (M_star * pp_sat_secondary);
938  int it = 0;
939  double f = 1., df_dvs, pp_sec, p_sec, dp_dT_sec, dp_dv_sec, dp_dT, dp_dv;
940  double tol_p = 1.e-8;
941  while (std::fabs(f / pp_sat_secondary) > tol_p)
942  {
943  pp_sec = 0.;
944  dp_dT = 0.;
945  dp_dv = 0.;
946  for (unsigned int i = 0; i < _n_secondary_vapors; i++)
947  {
948  _fp_secondary[i]->p_from_T_v(T, v_secondary / x_sec[i], p_sec, dp_dT_sec, dp_dv_sec);
949  pp_sec += p_sec;
950  dp_dT += dp_dT_sec;
951  dp_dv += dp_dv_sec / x_sec[i];
952  }
953  f = pp_sec - pp_sat_secondary;
954  df_dvs = dp_dv;
955  v_secondary -= f / df_dvs;
956  if (it++ > 15)
957  return getNaN();
958  }
959  }
960 
961  xs = v_secondary / (v_primary + v_secondary);
962  }
963 
964  return xs;
965 }
IdealRealGasMixtureFluidProperties::c_from_p_T
virtual Real c_from_p_T(Real p, Real T, const std::vector< Real > &x) const override
Speed of sound from pressure and temperature.
Definition: IdealRealGasMixtureFluidProperties.C:265
IdealRealGasMixtureFluidProperties::v_from_p_T
virtual Real v_from_p_T(Real p, Real T, const std::vector< Real > &x) const
Specific volume from pressure and temperature.
Definition: IdealRealGasMixtureFluidProperties.C:170
SinglePhaseFluidProperties::v_e_spndl_from_T
virtual void v_e_spndl_from_T(Real T, Real &v, Real &e) const
Specific internal energy from temperature and specific volume.
Definition: SinglePhaseFluidProperties.C:292
IdealRealGasMixtureFluidProperties::_T_mix_max
const Real _T_mix_max
maximum temperature of all components
Definition: IdealRealGasMixtureFluidProperties.h:552
IdealRealGasMixtureFluidProperties::T_from_p_v
Real T_from_p_v(Real p, Real v, const std::vector< Real > &x) const
Temperature from pressure and specific volume.
Definition: IdealRealGasMixtureFluidProperties.C:525
SinglePhaseFluidProperties::criticalInternalEnergy
virtual Real criticalInternalEnergy() const
Critical specific internal energy.
Definition: SinglePhaseFluidProperties.C:126
IdealRealGasMixtureFluidProperties::mu_from_p_T
virtual Real mu_from_p_T(Real p, Real T, const std::vector< Real > &x) const override
Dynamic viscosity from pressure and temperature.
Definition: IdealRealGasMixtureFluidProperties.C:362
IdealRealGasMixtureFluidProperties::mu_from_T_v
Real mu_from_T_v(Real T, Real v, const std::vector< Real > &x) const
Dynamic viscosity from temperature and specific volume.
Definition: IdealRealGasMixtureFluidProperties.C:848
SinglePhaseFluidProperties.h
IdealRealGasMixtureFluidProperties::k_from_p_T
virtual Real k_from_p_T(Real p, Real T, const std::vector< Real > &x) const override
Thermal conductivity from pressure and temperature.
Definition: IdealRealGasMixtureFluidProperties.C:390
BrentsMethod::root
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's method.
Definition: BrentsMethod.C:61
registerMooseObject
registerMooseObject("FluidPropertiesApp", IdealRealGasMixtureFluidProperties)
VaporMixtureFluidProperties::primaryMassFraction
Real primaryMassFraction(const std::vector< Real > &x) const
Computes the mass fraction of the primary vapor given mass fractions of the secondary vapors.
Definition: VaporMixtureFluidProperties.C:29
IdealRealGasMixtureFluidProperties::cp_from_T_v
Real cp_from_T_v(Real T, Real v, const std::vector< Real > &x) const
Isobaric heat capacity from temperature and specific volume.
Definition: IdealRealGasMixtureFluidProperties.C:814
IdealRealGasMixtureFluidProperties::_fp_primary
const SinglePhaseFluidProperties * _fp_primary
Primary vapor fluid properties.
Definition: IdealRealGasMixtureFluidProperties.h:542
IdealRealGasMixtureFluidProperties::c_from_v_e
virtual Real c_from_v_e(Real v, Real e, const std::vector< Real > &x) const override
Speed of sound from specific volume and specific internal energy.
Definition: IdealRealGasMixtureFluidProperties.C:101
IdealRealGasMixtureFluidProperties
Class for fluid properties of an arbitrary vapor mixture.
Definition: IdealRealGasMixtureFluidProperties.h:26
IdealRealGasMixtureFluidProperties::p_from_v_e
virtual Real p_from_v_e(Real v, Real e, const std::vector< Real > &x) const override
Pressure from specific volume and specific internal energy.
Definition: IdealRealGasMixtureFluidProperties.C:55
IdealRealGasMixtureFluidProperties::p_from_T_v
Real p_from_T_v(Real T, Real v, const std::vector< Real > &x) const
Pressure from temperature and specific volume.
Definition: IdealRealGasMixtureFluidProperties.C:580
validParams< IdealRealGasMixtureFluidProperties >
InputParameters validParams< IdealRealGasMixtureFluidProperties >()
Definition: IdealRealGasMixtureFluidProperties.C:19
SinglePhaseFluidProperties::criticalTemperature
virtual Real criticalTemperature() const
Critical temperature.
Definition: SinglePhaseFluidProperties.C:114
IdealRealGasMixtureFluidProperties::k_from_T_v
Real k_from_T_v(Real T, Real v, const std::vector< Real > &x) const
Thermal conductivity from temperature and specific volume.
Definition: IdealRealGasMixtureFluidProperties.C:874
IdealRealGasMixtureFluidProperties::cp_from_p_T
virtual Real cp_from_p_T(Real p, Real T, const std::vector< Real > &x) const override
Isobaric heat capacity from pressure and temperature.
Definition: IdealRealGasMixtureFluidProperties.C:325
SinglePhaseFluidProperties::e_spndl_from_v
virtual Real e_spndl_from_v(Real v) const
Specific internal energy from temperature and specific volume.
Definition: SinglePhaseFluidProperties.C:286
name
const std::string name
Definition: Setup.h:21
IdealRealGasMixtureFluidProperties::xs_prim_from_p_T
Real xs_prim_from_p_T(Real p, Real T, const std::vector< Real > &x) const
Mass fraction of primary (condensable) component at saturation from pressure and temperature.
Definition: IdealRealGasMixtureFluidProperties.C:900
IdealRealGasMixtureFluidProperties::e_from_p_T
virtual Real e_from_p_T(Real p, Real T, const std::vector< Real > &x) const override
Specific internal energy from pressure and temperature.
Definition: IdealRealGasMixtureFluidProperties.C:232
SinglePhaseFluidProperties::criticalDensity
virtual Real criticalDensity() const
Critical density.
Definition: SinglePhaseFluidProperties.C:120
IdealRealGasMixtureFluidProperties::_fp_secondary_names
const std::vector< UserObjectName > _fp_secondary_names
Names of secondary vapor fluid properties.
Definition: IdealRealGasMixtureFluidProperties.h:546
IdealRealGasMixtureFluidProperties::s_from_T_v
void s_from_T_v(Real T, Real v, const std::vector< Real > &x, Real &s, Real &ds_dT, Real &ds_dv) const
Specific entropy and its derivatives from temperature and specific volume.
Definition: IdealRealGasMixtureFluidProperties.C:732
SinglePhaseFluidProperties::molarMass
virtual virtual std Real molarMass() const
Fluid name.
Definition: SinglePhaseFluidProperties.C:96
IdealRealGasMixtureFluidProperties::cv_from_p_T
virtual Real cv_from_p_T(Real p, Real T, const std::vector< Real > &x) const override
Isochoric heat capacity from pressure and temperature.
Definition: IdealRealGasMixtureFluidProperties.C:348
BrentsMethod.h
IdealRealGasMixtureFluidProperties::_fp_secondary
std::vector< const SinglePhaseFluidProperties * > _fp_secondary
Secondary vapor fluid properties.
Definition: IdealRealGasMixtureFluidProperties.h:544
IdealRealGasMixtureFluidProperties::_n_secondary_vapors
const unsigned int _n_secondary_vapors
Number of secondary vapors.
Definition: IdealRealGasMixtureFluidProperties.h:548
NaNInterface::getNaN
Real getNaN() const
Produces errors, warnings, or just quiet NaNs.
Definition: NaNInterface.h:48
validParams< VaporMixtureFluidProperties >
InputParameters validParams< VaporMixtureFluidProperties >()
Definition: VaporMixtureFluidProperties.C:14
IdealRealGasMixtureFluidProperties::e_from_T_v
Real e_from_T_v(Real T, Real v, const std::vector< Real > &x) const
Specific internal energy from temperature and specific volume.
Definition: IdealRealGasMixtureFluidProperties.C:666
IdealRealGasMixtureFluidProperties::e_from_p_rho
virtual Real e_from_p_rho(Real p, Real rho, const std::vector< Real > &x) const override
Specific internal energy from pressure and density.
Definition: IdealRealGasMixtureFluidProperties.C:418
IdealRealGasMixtureFluidProperties::IdealRealGasMixtureFluidProperties
IdealRealGasMixtureFluidProperties(const InputParameters &parameters)
Definition: IdealRealGasMixtureFluidProperties.C:39
NaNInterface
Interface class for producing errors, warnings, or just quiet NaNs.
Definition: NaNInterface.h:27
validParams< NaNInterface >
InputParameters validParams< NaNInterface >()
Definition: NaNInterface.C:16
IdealRealGasMixtureFluidProperties::c_from_T_v
Real c_from_T_v(Real T, Real v, const std::vector< Real > &x) const
Speed of sound from temperature and specific volume.
Definition: IdealRealGasMixtureFluidProperties.C:756
IdealRealGasMixtureFluidProperties::rho_from_p_T
virtual Real rho_from_p_T(Real p, Real T, const std::vector< Real > &x) const override
Density from pressure and temperature.
Definition: IdealRealGasMixtureFluidProperties.C:142
VaporMixtureFluidProperties
Base class for fluid properties of vapor mixtures.
Definition: VaporMixtureFluidProperties.h:27
IdealRealGasMixtureFluidProperties::p_T_from_v_e
void p_T_from_v_e(Real v, Real e, const std::vector< Real > &x, Real &p, Real &T) const
Pressure and temperature from specific volume and specific internal energy.
Definition: IdealRealGasMixtureFluidProperties.C:457
IdealRealGasMixtureFluidProperties::R_molar
constexpr static const Real R_molar
molar (or universal) gas constant
Definition: IdealRealGasMixtureFluidProperties.h:550
IdealRealGasMixtureFluidProperties::T_from_v_e
virtual Real T_from_v_e(Real v, Real e, const std::vector< Real > &x) const override
Temperature from specific volume and specific internal energy.
Definition: IdealRealGasMixtureFluidProperties.C:78
BrentsMethod::bracket
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
IdealRealGasMixtureFluidProperties::cv_from_T_v
Real cv_from_T_v(Real T, Real v, const std::vector< Real > &x) const
Isochoric heat capacity from temperature and specific volume.
Definition: IdealRealGasMixtureFluidProperties.C:836
IdealRealGasMixtureFluidProperties.h