https://mooseframework.inl.gov
Loading...
Searching...
No Matches
CaloricallyImperfectGas.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#include "Conversion.h"
12#include "metaphysicl/raw_type.h"
13#include "Function.h"
14#include "BrentsMethod.h"
15
17
20{
22 params += NaNInterface::validParams();
23
24 params.addRequiredParam<Real>("molar_mass", "Constant molar mass of the fluid [kg/mol]");
25 params.addRequiredParam<FunctionName>("mu", "Dynamic viscosity, [Pa-s]");
26 params.addRequiredParam<FunctionName>("k", "Thermal conductivity, [W/(m-K)]");
27 params.addParam<Real>("T_c", 0, "Critical temperature, [K]");
28 params.addParam<Real>("rho_c", 0, "Critical density, [kg/m3]");
29 params.addParam<Real>("e_c", 0, "Specific internal energy at the critical point, [J/kg]");
30 params.addRequiredParam<FunctionName>(
31 "e", "Specific internal energy as a function of temperature [J/kg]");
32 params.addRequiredParam<Real>("min_temperature", "Smallest temperature for lookup tables [K]");
33 params.addRequiredParam<Real>("max_temperature", "Largest temperature for lookup tables [K]");
34 params.addParam<Real>(
35 "temperature_resolution", 1, "Step size in temperature for creating the inverse lookup T(e)");
36 params.addParam<bool>("out_of_bound_error", true, "Error if out of bounds");
37 params.addClassDescription("Fluid properties for an ideal gas with imperfect caloric behavior.");
38
39 return params;
40}
41
43 : SinglePhaseFluidProperties(parameters),
44 NaNInterface(this),
45 _molar_mass(getParam<Real>("molar_mass")),
46 _R_specific(_R / _molar_mass),
47 _T_c(getParam<Real>("T_c")),
48 _rho_c(getParam<Real>("rho_c")),
49 _e_c(getParam<Real>("e_c")),
50 _min_temperature(getParam<Real>("min_temperature")),
51 _max_temperature(getParam<Real>("max_temperature")),
52 _delta_T(getParam<Real>("temperature_resolution")),
53 _out_of_bound_error(getParam<bool>("out_of_bound_error")),
54 _tol(1e-4)
55{
56}
57
58void
68
69void
71{
72 // estimate number of points in inverse lookup & then adjust
73 // the _delta_T so (n - 1) * _delta_T = _max_temperature - _min_temperature
74 unsigned int n = std::floor((_max_temperature - _min_temperature) / _delta_T) + 1;
75 _delta_T = (_max_temperature - _min_temperature) / ((Real)n - 1.0);
76
77 // ensure e(T) is monotonic
78 for (unsigned int j = 0; j < n; ++j)
79 {
80 Real temperature = _min_temperature + j * _delta_T;
81
82 // Note that the function behavior at the end points
83 // can lead to de/dT = 0 & we want to allow that
84 Real cv = _e_T->timeDerivative(temperature, Point());
85 if (cv < 0 || (cv == 0 && j > 0 && j < n - 1))
86 mooseError("e(T) is not monotonically increasing with T");
87 }
88
89 // backward lookup tables
90 _min_e = _e_T->value(_min_temperature, Point());
91 _max_e = _e_T->value(_max_temperature, Point());
92 _delta_e = (_max_e - _min_e) / ((Real)n - 1.0);
95 _delta_h = (_max_h - _min_h) / ((Real)n - 1.0);
96
97 _T_e_lookup.resize(n);
98 _T_h_lookup.resize(n);
99 _Z_T_lookup.resize(n);
100 for (unsigned int j = 0; j < n; ++j)
101 {
102 // internal energy
103 {
104 Real internal_energy = _min_e + j * _delta_e;
105
106 // guarding against roundoff when summing
107 // at least once I saw roundoff cause an error here
108 internal_energy = std::min(internal_energy, _max_e);
109
110 // The temperature is found by e - e(T) = 0
111 Real min = _min_temperature;
112 Real max = _max_temperature;
113 auto e_diff = [&internal_energy, this](Real x)
114 { return this->e_from_p_T(0.0, x) - internal_energy; };
115 BrentsMethod::bracket(e_diff, min, max);
116 Real temperature = BrentsMethod::root(e_diff, min, max);
117 _T_e_lookup[j] = temperature;
118 }
119
120 // enthalpy
121 {
122 Real enthalpy = _min_h + j * _delta_h;
123
124 // guarding against roundoff when summing
125 // at least once I saw roundoff cause an error here
126 enthalpy = std::min(enthalpy, _max_h);
127
128 // The temperature is found by h - h(T) = 0
129 Real min = _min_temperature;
130 Real max = _max_temperature;
131 auto h_diff = [&enthalpy, this](Real x) { return this->h_from_p_T(0.0, x) - enthalpy; };
132 BrentsMethod::bracket(h_diff, min, max);
133 Real temperature = BrentsMethod::root(h_diff, min, max);
134 _T_h_lookup[j] = temperature;
135 }
136
137 // Z(T)
138 {
139 if (j == 0)
140 _Z_T_lookup[j] = 0;
141 else
142 {
143 Real temperature = _min_temperature + j * _delta_T;
144 Real temperature_prev = _min_temperature + (j - 1) * _delta_T;
145 Real f1 = cv_from_T(temperature) / temperature;
146 Real f2 = cv_from_T(temperature_prev) / temperature_prev;
147 _Z_T_lookup[j] = _Z_T_lookup[j - 1] + 0.5 * _delta_T * (f1 + f2);
148 }
149 }
150 }
151}
152
153std::string
155{
156 return "caloric_imperfect_gas";
157}
158
159Real
161{
162 if (T < _min_temperature || T > _max_temperature)
164
165 return _e_T->value(T, Point());
166}
167
168Real
170{
171 if (T < _min_temperature || T > _max_temperature)
173 return _e_T->value(T, Point()) + _R_specific * T;
174}
175
176Real
178{
179 if (T < _min_temperature || T > _max_temperature)
181
182 return _e_T->timeDerivative(T, Point()) + _R_specific;
183}
184
185void
186CaloricallyImperfectGas::cv_from_T(Real T, Real & cv, Real & dcv_dT) const
187{
188 if (T < _min_temperature || T > _max_temperature)
189 outOfBounds("cv_from_T (3 args)", T, _min_temperature, _max_temperature);
190 Real pert = 1.0e-7;
191 cv = cv_from_T(T);
192 Real cv_pert = cv_from_T(T * (1 + pert));
193 dcv_dT = (cv_pert - cv) / (T * pert);
194}
195
196void
197CaloricallyImperfectGas::cp_from_T(Real T, Real & cp, Real & dcp_dT) const
198{
199 if (T < _min_temperature || T > _max_temperature)
200 outOfBounds("cp_from_T (3 args)", T, _min_temperature, _max_temperature);
201 Real pert = 1.0e-7;
202 cp = cp_from_T(T);
203 Real cp_pert = cp_from_T(T * (1 + pert));
204 dcp_dT = (cp_pert - cp) / (T * pert);
205}
206
207Real
209{
210 if (e < _min_e || e > _max_e)
211 outOfBounds("T_from_e", e, _min_e, _max_e);
212
213 if (e < _min_e)
214 return _T_e_lookup[0];
215 else if (e > _max_e)
216 return _T_e_lookup.back();
217
218 unsigned int index = std::floor((e - _min_e) / _delta_e);
219 Real x = (e - _min_e - index * _delta_e) / _delta_e;
220 return x * _T_e_lookup[index + 1] + (1 - x) * _T_e_lookup[index];
221}
222
223Real
225{
226 if (h < _min_h || h > _max_h)
227 outOfBounds("h_from_e", h, _min_h, _max_h);
228
229 if (h < _min_h)
230 return _T_h_lookup[0];
231 else if (h > _max_h)
232 return _T_h_lookup.back();
233
234 unsigned int index = std::floor((h - _min_h) / _delta_h);
235 Real x = (h - _min_h - index * _delta_h) / _delta_h;
236 return x * _T_h_lookup[index + 1] + (1 - x) * _T_h_lookup[index];
237}
238
239Real
241{
242 if (T < _min_temperature || T > _max_temperature)
244
245 unsigned int index = std::floor((T - _min_temperature) / _delta_T);
246 Real x = (T - _min_temperature - index * _delta_T) / _delta_T;
247 return x * _Z_T_lookup[index + 1] + (1 - x) * _Z_T_lookup[index];
248}
249
250Real
252{
253 if (v == 0.0)
254 return getNaN("Invalid value of specific volume detected (v = " + Moose::stringify(v) + ").");
255
256 return _R_specific * T_from_e(e) / v;
257}
258
259ADReal
261{
262 if (v.value() == 0.0)
263 return getNaN("Invalid value of specific volume detected (v = " + Moose::stringify(v.value()) +
264 ").");
265
266 Real x = 0;
267 Real raw1 = v.value();
268 Real raw2 = e.value();
269 Real dxd1 = 0;
270 Real dxd2 = 0;
271 p_from_v_e(raw1, raw2, x, dxd1, dxd2);
272
273 ADReal result = x;
274 result.derivatives() = v.derivatives() * dxd1 + e.derivatives() * dxd2;
275 return result;
276}
277
278void
279CaloricallyImperfectGas::p_from_v_e(Real v, Real e, Real & p, Real & dp_dv, Real & dp_de) const
280{
281 p = p_from_v_e(v, e);
282 Real T = T_from_e(e);
283 dp_dv = -_R_specific * T / v / v;
284 dp_de = _R_specific / v / cv_from_T(T);
285}
286
287Real
288CaloricallyImperfectGas::T_from_v_e(Real /*v*/, Real e) const
289{
290 return T_from_e(e);
291}
292
293ADReal
295{
296 if (v.value() == 0.0)
297 return getNaN("Invalid value of specific volume detected (v = " + Moose::stringify(v.value()) +
298 ").");
299
300 Real x = 0;
301 Real raw1 = v.value();
302 Real raw2 = e.value();
303 Real dxd1 = 0;
304 Real dxd2 = 0;
305 T_from_v_e(raw1, raw2, x, dxd1, dxd2);
306
307 ADReal result = x;
308 result.derivatives() = v.derivatives() * dxd1 + e.derivatives() * dxd2;
309 return result;
310}
311
312void
313CaloricallyImperfectGas::T_from_v_e(Real v, Real e, Real & T, Real & dT_dv, Real & dT_de) const
314{
315 T = T_from_e(e);
316 dT_dv = 0.0;
317 dT_de = 1.0 / cv_from_v_e(v, e);
318}
319
320Real
322{
323 Real T = T_from_v_e(v, e);
324
325 const Real c2 = gamma_from_v_e(v, e) * _R_specific * T;
326 if (c2 < 0)
327 return getNaN("Sound speed squared (gamma * R * T) is negative: c2 = " + Moose::stringify(c2) +
328 ".");
329
330 return std::sqrt(c2);
331}
332
333ADReal
335{
336 using std::sqrt;
337 const auto T = T_from_v_e(v, e);
338
339 const auto c2 = gamma_from_v_e(v, e) * _R_specific * T;
340 if (MetaPhysicL::raw_value(c2) < 0)
341 return getNaN("Sound speed squared (gamma * R * T) is negative: c2 = " +
343
344 return sqrt(c2);
345}
346
347void
348CaloricallyImperfectGas::c_from_v_e(Real v, Real e, Real & c, Real & dc_dv, Real & dc_de) const
349{
350 Real T, dT_dv, dT_de;
351 T_from_v_e(v, e, T, dT_dv, dT_de);
352
353 Real gamma, dgamma_dv, dgamma_dT;
354 gamma_from_v_e(v, e, gamma, dgamma_dv, dgamma_dT);
355 c = std::sqrt(gamma * _R_specific * T);
356
357 const Real dc_dT = 0.5 / c * _R_specific * (gamma + T * dgamma_dT);
358 dc_dv = dc_dT * dT_dv;
359 dc_de = dc_dT * dT_de;
360}
361
362Real
364{
365 return std::sqrt(gamma_from_p_T(p, T) * _R_specific * T);
366}
367
368ADReal
370{
371 using std::sqrt;
372 return sqrt(gamma_from_p_T(p, T) * _R_specific * T);
373}
374
375void
377 const Real p, const Real T, Real & c, Real & dc_dp, Real & dc_dT) const
378{
379 Real gamma, dgamma_dp, dgamma_dT;
380 gamma_from_p_T(p, T, gamma, dgamma_dp, dgamma_dT);
381 c = std::sqrt(gamma * _R_specific * T);
382 dc_dp = 0;
383 dc_dT = 0.5 / c * _R_specific * (gamma + T * dgamma_dT);
384}
385
386Real
388{
389 Real T = T_from_v_e(v, e);
390 return cp_from_T(T);
391}
392
393void
394CaloricallyImperfectGas::cp_from_v_e(Real v, Real e, Real & cp, Real & dcp_dv, Real & dcp_de) const
395{
396 Real T = T_from_v_e(v, e);
397 Real dcp_dT;
398 cp_from_T(T, cp, dcp_dT);
399 dcp_dv = 0.0;
400 dcp_de = dcp_dT / cv_from_T(T);
401}
402
403Real
405{
406 Real T = T_from_v_e(v, e);
407 return cv_from_T(T);
408}
409
410ADReal
412{
413 Real x = 0;
414 Real raw1 = v.value();
415 Real raw2 = e.value();
416 Real dxd1 = 0;
417 Real dxd2 = 0;
418 cv_from_v_e(raw1, raw2, x, dxd1, dxd2);
419
420 ADReal result = x;
421 result.derivatives() = v.derivatives() * dxd1 + e.derivatives() * dxd2;
422 return result;
423}
424
425void
426CaloricallyImperfectGas::cv_from_v_e(Real v, Real e, Real & cv, Real & dcv_dv, Real & dcv_de) const
427{
428 Real T = T_from_v_e(v, e);
429 Real dcv_dT;
430 cv_from_T(T, cv, dcv_dT);
431 dcv_dv = 0.0;
432 dcv_de = dcv_dT / cv;
433}
434
435Real
437{
438 return cp_from_v_e(v, e) / cv_from_v_e(v, e);
439}
440
441ADReal
443{
444 Real x = 0;
445 Real raw1 = v.value();
446 Real raw2 = e.value();
447 Real dxd1 = 0;
448 Real dxd2 = 0;
449 gamma_from_v_e(raw1, raw2, x, dxd1, dxd2);
450
451 ADReal result = x;
452 result.derivatives() = v.derivatives() * dxd1 + e.derivatives() * dxd2;
453 return result;
454}
455
456void
458 Real v, Real e, Real & gamma, Real & dgamma_dv, Real & dgamma_de) const
459{
460 Real cp, dcp_dv, dcp_de;
461 cp_from_v_e(v, e, cp, dcp_dv, dcp_de);
462 Real cv, dcv_dv, dcv_de;
463 cv_from_v_e(v, e, cv, dcv_dv, dcv_de);
464 gamma = cp / cv;
465 dgamma_dv = 0.0;
466 dgamma_de = 1.0 / cv * dcp_de - gamma / cv * dcv_de;
467}
468
469void
471 Real p, Real T, Real & gamma, Real & dgamma_dp, Real & dgamma_dT) const
472{
473 Real cp, dcp_dp, dcp_dT;
474 cp_from_p_T(p, T, cp, dcp_dp, dcp_dT);
475 Real cv, dcv_dp, dcv_dT;
476 cv_from_p_T(p, T, cv, dcv_dp, dcv_dT);
477 gamma = cp / cv;
478 dgamma_dp = 0.0;
479 dgamma_dT = 1.0 / cv * dcp_dT - gamma / cv * dcv_dT;
480}
481
482Real
484{
485 return cp_from_p_T(p, T) / cv_from_p_T(p, T);
486}
487
488ADReal
490{
491 Real x = 0;
492 Real raw1 = p.value();
493 Real raw2 = T.value();
494 Real dxd1 = 0;
495 Real dxd2 = 0;
496 gamma_from_p_T(raw1, raw2, x, dxd1, dxd2);
497 ADReal result = x;
498 result.derivatives() = p.derivatives() * dxd1 + T.derivatives() * dxd2;
499 return result;
500}
501
502Real
504{
505 const Real T = T_from_v_e(v, e);
506 const Real p = p_from_v_e(v, e);
507 return mu_from_p_T(p, T);
508}
509
510void
511CaloricallyImperfectGas::mu_from_v_e(Real v, Real e, Real & mu, Real & dmu_dv, Real & dmu_de) const
512{
513 const Real T = T_from_v_e(v, e);
514 const Real p = p_from_v_e(v, e);
515 Real dmu_dp, dmu_dT;
516 mu_from_p_T(p, T, mu, dmu_dp, dmu_dT);
517 // only dmu_de = dmu/dT * dT/de = 1/cv * dmu/dT is nonzero
518 // (dmu/dv)_e = 0 because e only depends on T and e is constant
519 dmu_dv = 0.0;
520 dmu_de = dmu_dT / cv_from_p_T(p, T);
521}
522
523Real
525{
526 const Real T = T_from_v_e(v, e);
527 const Real p = p_from_v_e(v, e);
528 return k_from_p_T(p, T);
529}
530
531void
532CaloricallyImperfectGas::k_from_v_e(Real v, Real e, Real & k, Real & dk_dv, Real & dk_de) const
533{
534 const Real T = T_from_v_e(v, e);
535 const Real p = p_from_v_e(v, e);
536 Real dk_dp, dk_dT;
537 k_from_p_T(p, T, k, dk_dp, dk_dT);
538 // only dk_de = dk/dT * dT/de = 1/cv * dk/dT is nonzero
539 // (dk/dv)_e = 0 because e only depends on T and e is constant
540 dk_dv = 0.0;
541 dk_de = dk_dT / cv_from_p_T(p, T);
542}
543
544Real
546{
547 Real T = T_from_v_e(v, e);
548 Real Z = Z_from_T(T);
549 return Z + _R_specific * std::log(v);
550}
551
552void
553CaloricallyImperfectGas::s_from_v_e(Real v, Real e, Real & s, Real & ds_dv, Real & ds_de) const
554{
555 s = s_from_v_e(v, e);
556 // see documentation for derivation
557 ds_dv = _R_specific / v;
558 ds_de = 1.0 / T_from_v_e(v, e);
559}
560
561Real
563{
564 Real Z = Z_from_T(T);
565 Real v = 1.0 / rho_from_p_T(p, T);
566 return Z + _R_specific * std::log(v);
567}
568
569void
570CaloricallyImperfectGas::s_from_p_T(Real p, Real T, Real & s, Real & ds_dp, Real & ds_dT) const
571{
572 s = s_from_p_T(p, T);
573 ds_dp = -_R_specific / p;
574 ds_dT = cp_from_p_T(p, T) / T;
575}
576
577Real
579{
580 Real T = T_from_p_h(p, h);
581 Real v = 1.0 / rho_from_p_T(p, T);
582 Real Z = Z_from_T(T);
583 return Z + _R_specific * std::log(v);
584}
585
586void
587CaloricallyImperfectGas::s_from_h_p(Real h, Real p, Real & s, Real & ds_dh, Real & ds_dp) const
588{
589 s = s_from_h_p(h, p);
590 ds_dh = 1.0 / T_from_p_h(p, h);
591 ds_dp = -_R_specific / p;
592}
593
594Real
596{
597 auto s_diff = [&p, &s, this](Real x) { return this->s_from_p_T(p, x) - s; };
598 Real min = _min_temperature;
599 Real max = _max_temperature;
600 BrentsMethod::bracket(s_diff, min, max);
601 Real T = BrentsMethod::root(s_diff, min, max);
602 return rho_from_p_T(p, T);
603}
604
605Real
606CaloricallyImperfectGas::e_from_v_h(Real /*v*/, Real h) const
607{
608 Real T = T_from_h(h);
609 return e_from_T(T);
610}
611
612void
613CaloricallyImperfectGas::e_from_v_h(Real v, Real h, Real & e, Real & de_dv, Real & de_dh) const
614{
615 e = e_from_v_h(v, h);
616 Real cv = cv_from_v_e(v, e);
617 Real cp = cp_from_v_e(v, e);
618 de_dv = 0.0;
619 de_dh = cv / cp;
620}
621
622Real
624{
625 return p * _molar_mass / (_R * T);
626}
627
628ADReal
630{
631 return p * _molar_mass / (_R * T);
632}
633
634void
636 const ADReal & p, const ADReal & T, ADReal & rho, ADReal & drho_dp, ADReal & drho_dT) const
637{
638 rho = rho_from_p_T(p, T);
639 drho_dp = _molar_mass / (_R * T);
640 drho_dT = -p * _molar_mass / (_R * T * T);
641}
642
643void
645 Real p, Real T, Real & rho, Real & drho_dp, Real & drho_dT) const
646{
647 rho = rho_from_p_T(p, T);
648 drho_dp = _molar_mass / (_R * T);
649 drho_dT = -p * _molar_mass / (_R * T * T);
650}
651
652Real
653CaloricallyImperfectGas::e_from_p_rho(Real p, Real rho) const
654{
655 return e_from_p_rho_template(p, rho);
656}
657
658ADReal
659CaloricallyImperfectGas::e_from_p_rho(const ADReal & p, const ADReal & rho) const
660{
661 return e_from_p_rho_template(p, rho);
662}
663
664void
665CaloricallyImperfectGas::e_from_p_rho(
666 Real p, Real rho, Real & e, Real & de_dp, Real & de_drho) const
667{
668 e_from_p_rho_template(p, rho, e, de_dp, de_drho);
669}
670
671void
672CaloricallyImperfectGas::e_from_p_rho(
673 const ADReal & p, const ADReal & rho, ADReal & e, ADReal & de_dp, ADReal & de_drho) const
674{
675 e_from_p_rho_template(p, rho, e, de_dp, de_drho);
676}
677
678Real
680{
681 return e_from_T(T);
682}
683
684void
685CaloricallyImperfectGas::e_from_T_v(Real T, Real v, Real & e, Real & de_dT, Real & de_dv) const
686{
687 e = e_from_T_v(T, v);
688 de_dT = cv_from_T_v(T, v);
689 de_dv = 0.0;
690}
691
692ADReal
694{
695 Real x = 0;
696 Real raw1 = T.value();
697 Real raw2 = v.value();
698 Real dxd1 = 0;
699 Real dxd2 = 0;
700 e_from_T_v(raw1, raw2, x, dxd1, dxd2);
701
702 ADReal result = x;
703 result.derivatives() = T.derivatives() * dxd1 + v.derivatives() * dxd2;
704 return result;
705}
706
707Real
709{
710 return _R_specific * T / v;
711}
712
713void
714CaloricallyImperfectGas::p_from_T_v(Real T, Real v, Real & p, Real & dp_dT, Real & dp_dv) const
715{
716 p = _R_specific * T / v;
717 dp_dT = _R_specific / v;
718 dp_dv = -_R_specific * T / (v * v);
719}
720
721Real
723{
724 return h_from_T(T);
725}
726
727void
728CaloricallyImperfectGas::h_from_T_v(Real T, Real /*v*/, Real & h, Real & dh_dT, Real & dh_dv) const
729{
730 h = h_from_T(T);
731 dh_dT = cp_from_T(T);
732 dh_dv = 0.0;
733}
734
735Real
737{
738 Real p = p_from_T_v(T, v);
739 return s_from_p_T(p, T);
740}
741
742void
743CaloricallyImperfectGas::s_from_T_v(Real T, Real v, Real & s, Real & ds_dT, Real & ds_dv) const
744{
745 Real p, dp_dT_v, dp_dv_T;
746 Real ds_dp_T, ds_dT_p;
747 p_from_T_v(T, v, p, dp_dT_v, dp_dv_T);
748 s_from_p_T(p, T, s, ds_dp_T, ds_dT_p);
749 ds_dT = ds_dT_p + ds_dp_T * dp_dT_v;
750 ds_dv = ds_dp_T * dp_dv_T;
751}
752
753Real
755{
756 return cv_from_T(T);
757}
758
759Real
761{
762 return _e_c;
763}
764
765void
766CaloricallyImperfectGas::v_e_spndl_from_T(Real /*T*/, Real & v, Real & e) const
767{
768 v = 1. / _rho_c;
769 e = _e_c;
770}
771
772Real
774{
775 return h_from_T(T);
776}
777
778void
779CaloricallyImperfectGas::h_from_p_T(Real p, Real T, Real & h, Real & dh_dp, Real & dh_dT) const
780{
781 h = h_from_p_T(p, T);
782 dh_dp = 0.0;
783 dh_dT = cp_from_p_T(p, T);
784}
785
786Real
788{
789 return e_from_T(T);
790}
791
792ADReal
794{
795 Real x = 0;
796 Real raw1 = p.value();
797 Real raw2 = T.value();
798 Real dxd1 = 0;
799 Real dxd2 = 0;
800 e_from_p_T(raw1, raw2, x, dxd1, dxd2);
801
802 ADReal result = x;
803 result.derivatives() = p.derivatives() * dxd1 + T.derivatives() * dxd2;
804 return result;
805}
806
807void
808CaloricallyImperfectGas::e_from_p_T(Real p, Real T, Real & e, Real & de_dp, Real & de_dT) const
809{
810 e = e_from_p_T(p, T);
811 de_dp = 0.0;
812 de_dT = cv_from_p_T(p, T);
813}
814
815Real
820
821Real
826
827Real
832
833Real
838
839Real
840CaloricallyImperfectGas::T_from_p_h(Real /*p*/, Real h) const
841{
842 return T_from_h(h);
843}
844
845void
846CaloricallyImperfectGas::T_from_p_h(Real p, Real h, Real & T, Real & dT_dp, Real & dT_dh) const
847{
848 T = T_from_p_h(p, h);
849 dT_dp = 0;
850 dT_dh = 1.0 / cp_from_p_T(p, T);
851}
852
853Real
854CaloricallyImperfectGas::cv_from_p_T(Real /* pressure */, Real temperature) const
855{
856 return cv_from_T(temperature);
857}
858
859void
861 Real /*p*/, Real T, Real & cv, Real & dcv_dp, Real & dcv_dT) const
862{
863 cv_from_T(T, cv, dcv_dT);
864 dcv_dp = 0.0;
865}
866
867Real
868CaloricallyImperfectGas::cp_from_p_T(Real /* pressure */, Real temperature) const
869{
870 return cp_from_T(temperature);
871}
872
873void
875 Real /*p*/, Real T, Real & cp, Real & dcp_dp, Real & dcp_dT) const
876{
877 cp_from_T(T, cp, dcp_dT);
878 dcp_dp = 0.0;
879}
880
881Real
882CaloricallyImperfectGas::mu_from_p_T(Real /* pressure */, Real temperature) const
883{
884 return _mu_T->value(temperature, Point());
885}
886
887void
888CaloricallyImperfectGas::mu_from_p_T(Real p, Real T, Real & mu, Real & dmu_dp, Real & dmu_dT) const
889{
890 mu = this->mu_from_p_T(p, T);
891 dmu_dp = 0.0;
892 Real pert = 1.0e-7;
893 Real mu2 = this->mu_from_p_T(p, T * (1 + pert));
894 dmu_dT = (mu2 - mu) / (T * pert);
895}
896
897Real
898CaloricallyImperfectGas::k_from_p_T(Real /* pressure */, Real temperature) const
899{
900 return _k_T->value(temperature, Point());
901}
902
903void
904CaloricallyImperfectGas::k_from_p_T(Real p, Real T, Real & k, Real & dk_dp, Real & dk_dT) const
905{
906 k = k_from_p_T(p, T);
907 dk_dp = 0.0;
908 Real pert = 1.0e-7;
909 Real k2 = this->k_from_p_T(p, T * (1 + pert));
910 dk_dT = (k2 - k) / (T * pert);
911}
912
913Real
915{
916 // use the definition of the Gibbs free energy
917 Real T = T_from_v_e(v, e);
918 Real p = p_from_v_e(v, e);
919 return h_from_p_T(p, T) - T * s_from_p_T(p, T);
920}
921
922Real
924{
925 Real T = T_from_h(h);
926 Real e = e_from_T(T);
927 Real Z = Z_from_T(T);
928 Real v = std::exp((s - Z) / _R_specific);
929 return p_from_v_e(v, e);
930}
931
932void
933CaloricallyImperfectGas::p_from_h_s(Real h, Real s, Real & p, Real & dp_dh, Real & dp_ds) const
934{
935 p = p_from_h_s(h, s);
936 Real pert = 1e-7;
937 Real p_pert = p_from_h_s(h * (1 + pert), s);
938 dp_dh = (p_pert - p) / (h * pert);
939 p_pert = p_from_h_s(h, s * (1 + pert));
940 dp_ds = (p_pert - p) / (s * pert);
941}
942
943void
944CaloricallyImperfectGas::outOfBounds(const std::string & function,
945 Real value,
946 Real min,
947 Real max) const
948{
949 std::stringstream ss;
950 ss << "Function " << function << " encountered argument value of " << value
951 << " which is outside of the bounds of " << min << " .. " << max;
953 mooseError(ss.str());
954 else
955 mooseWarning(ss.str());
956}
DualNumber< Real, DNDerivativeType, true > ADReal
registerMooseObject("FluidPropertiesApp", CaloricallyImperfectGas)
const std::vector< double > x
const double mu
const Real p
const double rho
const double T
const double v
A calorically imperfect gas fluid property class This fluid property assumes that internal energy is ...
Real _min_temperature
temperature limits when creating lookup tables
const Function * _k_T
Thermal conductivity.
virtual Real e_from_v_h(Real v, Real h) const override
virtual Real p_from_v_e(Real v, Real e) const override
virtual Real s_from_v_e(Real v, Real e) const override
virtual Real c_from_p_T(Real p, Real T) const override
virtual Real cv_from_v_e(Real v, Real e) const override
virtual Real gamma_from_p_T(Real p, Real T) const override
virtual Real rho_from_p_s(Real p, Real s) const override
const bool _out_of_bound_error
Flag to error if out of bounds.
virtual void initialSetup() override
virtual Real mu_from_p_T(Real p, Real T) const override
virtual Real criticalDensity() const override
Critical density.
virtual Real criticalInternalEnergy() const override
Critical specific internal energy.
virtual Real cv_from_T_v(Real T, Real v) const override
virtual void v_e_spndl_from_T(Real T, Real &v, Real &e) const override
Specific internal energy from temperature and specific volume.
virtual Real cp_from_v_e(Real v, Real e) const override
virtual Real e_spndl_from_v(Real v) const override
Specific internal energy from temperature and specific volume.
virtual Real k_from_p_T(Real pressure, Real temperature) const override
virtual Real e_from_p_T(Real p, Real T) const override
const Function * _mu_T
Dynamic viscosity.
Real e_from_T(Real T) const
helper functions for e(T) and h(T), T(e), T(h), cv(T), cp(T)
std::vector< Real > _T_h_lookup
inverse lookup table data
Real _delta_T
temperature interval in lookup tables
virtual Real s_from_T_v(Real T, Real v) const override
virtual Real h_from_p_T(Real p, Real T) const override
virtual Real e_from_T_v(Real T, Real v) const override
virtual Real h_from_T_v(Real T, Real v) const override
virtual Real T_from_v_e(Real v, Real e) const override
Real cv_from_T(const CppType &T) const
virtual Real g_from_v_e(Real v, Real e) const override
virtual Real s_from_h_p(Real h, Real p) const override
const Real & _molar_mass
molar mass
static InputParameters validParams()
Real _min_e
internal energy and enthalpy limits when creating lookup tables
CaloricallyImperfectGas(const InputParameters &parameters)
virtual Real cv_from_p_T(Real p, Real T) const override
virtual std::string fluidName() const override
Fluid name.
virtual Real T_from_p_h(Real p, Real h) const override
Real _delta_e
step size in internal energy and enthalpy
virtual Real c_from_v_e(Real v, Real e) const override
void outOfBounds(const std::string &function, Real value, Real min, Real max) const
function that handles exceeding parameter limits
virtual Real k_from_v_e(Real v, Real e) const override
virtual Real p_from_T_v(Real T, Real v) const override
virtual Real cp_from_p_T(Real p, Real T) const override
virtual Real criticalTemperature() const override
Critical temperature.
void setupLookupTables()
sets up the T(e) reverse lookup table
virtual Real rho_from_p_T(Real p, Real T) const override
virtual Real gamma_from_v_e(Real v, Real e) const override
const Function * _e_T
Internal energy as a function of temperature.
virtual Real molarMass() const override
Molar mass [kg/mol].
virtual Real s_from_p_T(Real p, Real T) const override
std::vector< Real > _Z_T_lookup
Z(T) lookup table on uniform grid between _min_temperature and _max_temperature.
virtual Real mu_from_v_e(Real v, Real e) const override
virtual Real p_from_h_s(Real h, Real s) const override
const Real _R_specific
Specific gas constant (R / molar mass)
static const Real _R
Universal gas constant (J/mol/K)
const Function & getFunction(const std::string &name) const
virtual Real value(Real t, const Point &p) const
virtual Real timeDerivative(Real t, const Point &p) const
void addRequiredParam(const std::string &name, const std::string &doc_string)
void addParam(const std::string &name, const std::initializer_list< typename T::value_type > &value, const std::string &doc_string)
void addClassDescription(const std::string &doc_string)
void mooseError(Args &&... args) const
void mooseWarning(Args &&... args) const
Interface class for producing errors, warnings, or just quiet NaNs.
Real getNaN() const
Throws an error or returns a NaN with or without a warning, with a default message.
static InputParameters validParams()
virtual void initialSetup()
Common class for single phase fluid properties.
static InputParameters validParams()
e e e e s T T T T T rho v v T e h
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.
void bracket(std::function< Real(Real)> const &f, Real &x1, Real &x2)
Function to bracket a root of a given function.
auto raw_value(const Eigen::Map< T > &in)
std::string stringify(const T &t)
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real