21 #define define_from_v_e_using_T_v(prop) \ 22 Real IdealRealGasMixtureFluidProperties::prop##_from_v_e( \ 23 Real v, Real e, const std::vector<Real> & x) const \ 25 const Real T = T_from_v_e(v, e, x); \ 26 return prop##_from_T_v(T, v, x); \ 29 void IdealRealGasMixtureFluidProperties::prop##_from_v_e(Real v, \ 31 const std::vector<Real> & x, \ 35 std::vector<Real> & dy_dx) const \ 37 Real T, dT_dv_e, dT_de_v; \ 38 std::vector<Real> dT_dx_ve(_n_secondary_vapors); \ 39 T_from_v_e(v, e, x, T, dT_dv_e, dT_de_v, dT_dx_ve); \ 41 Real dy_dT_v, dy_dv_T; \ 42 std::vector<Real> dy_dx_Tv; \ 43 prop##_from_T_v(T, v, x, y, dy_dT_v, dy_dv_T, dy_dx_Tv); \ 45 dy_dv = dy_dv_T + dy_dT_v * dT_dv_e; \ 46 dy_de = dy_dT_v * dT_de_v; \ 47 dy_dx.resize(_n_secondary_vapors); \ 48 for (unsigned int i = 0; i < _n_secondary_vapors; i++) \ 49 dy_dx[i] = dy_dx_Tv[i] + dy_dT_v * dT_dx_ve[i]; \ 56 #define define_from_p_T_using_T_v(prop) \ 57 Real IdealRealGasMixtureFluidProperties::prop##_from_p_T( \ 58 Real p, Real T, const std::vector<Real> & x) const \ 60 const Real v = v_from_p_T(p, T, x); \ 61 return prop##_from_T_v(T, v, x); \ 64 void IdealRealGasMixtureFluidProperties::prop##_from_p_T(Real p, \ 66 const std::vector<Real> & x, \ 70 std::vector<Real> & dy_dx) const \ 72 Real v, dv_dp_T, dv_dT_p; \ 73 std::vector<Real> dv_dx_pT; \ 74 v_from_p_T(p, T, x, v, dv_dp_T, dv_dT_p, dv_dx_pT); \ 76 Real dy_dT_v, dy_dv_T; \ 77 std::vector<Real> dy_dx_Tv; \ 78 prop##_from_T_v(T, v, x, y, dy_dT_v, dy_dv_T, dy_dx_Tv); \ 80 dy_dp = dy_dv_T * dv_dp_T; \ 81 dy_dT = dy_dT_v + dy_dv_T * dv_dT_p; \ 82 dy_dx.resize(_n_secondary_vapors); \ 83 for (unsigned int i = 0; i < _n_secondary_vapors; i++) \ 84 dy_dx[i] = dy_dx_Tv[i] + dy_dv_T * dv_dx_pT[i]; \ 90 #define define_mass_specific_prop_from_T_v(prop) \ 91 Real IdealRealGasMixtureFluidProperties::prop##_from_T_v( \ 92 Real T, Real v, const std::vector<Real> & x) const \ 94 const Real x_primary = primaryMassFraction(x); \ 95 Real y = x_primary * _fp_primary->prop##_from_T_v(T, v / x_primary); \ 97 for (unsigned int i = 0; i < _n_secondary_vapors; i++) \ 98 y += x[i] * _fp_secondary[i]->prop##_from_T_v(T, v / x[i]); \ 103 void IdealRealGasMixtureFluidProperties::prop##_from_T_v(Real T, \ 105 const std::vector<Real> & x, \ 109 std::vector<Real> & dy_dx) const \ 111 const Real x_primary = primaryMassFraction(x); \ 112 mooseAssert(!MooseUtils::absoluteFuzzyEqual(x_primary, 0.0), "Mass fraction may not be zero"); \ 114 Real y_primary, dy_dT_primary, dy_dv_primary; \ 115 _fp_primary->prop##_from_T_v(T, v / x_primary, y_primary, dy_dT_primary, dy_dv_primary); \ 116 y = x_primary * y_primary; \ 117 dy_dT = x_primary * dy_dT_primary; \ 118 dy_dv = dy_dv_primary; \ 121 std::vector<Real> y_sec(_n_secondary_vapors), dy_dv_sec(_n_secondary_vapors); \ 122 for (unsigned int i = 0; i < _n_secondary_vapors; i++) \ 124 mooseAssert(!MooseUtils::absoluteFuzzyEqual(x[i], 0.0), "Mass fraction may not be zero"); \ 125 _fp_secondary[i]->prop##_from_T_v(T, v / x[i], y_sec[i], dy_dT_sec, dy_dv_sec[i]); \ 126 y += x[i] * y_sec[i]; \ 127 dy_dT += x[i] * dy_dT_sec; \ 128 dy_dv += dy_dv_sec[i]; \ 131 dy_dx.resize(_n_secondary_vapors); \ 132 for (unsigned int i = 0; i < _n_secondary_vapors; i++) \ 134 dy_dx[i] = y_sec[i] - x[i] * dy_dv_sec[i] * v / (x[i] * x[i]); \ 135 for (unsigned int j = 0; j < _n_secondary_vapors; j++) \ 139 if (_n_secondary_vapors > 1) \ 140 imperfectJacobianMessage( \ 141 "The mass fraction derivatives in the following " \ 142 "function have not been tested for mixtures of 3 or more components:\n\n", \ 143 __PRETTY_FUNCTION__); \ 144 const Real dxj_dxi = 0; \ 145 dy_dx[i] += dxj_dxi * y_sec[j] - x[j] * dy_dv_sec[j] * v / (x[j] * x[j]) * dxj_dxi; \ 147 const Real dx_primary_dxi = -x_primary / (1. - x[i]); \ 148 dy_dx[i] += dx_primary_dxi * y_primary - \ 149 x_primary * dy_dv_primary * v / (x_primary * x_primary) * dx_primary_dxi; \ 156 #define define_transport_prop_from_T_v(prop) \ 157 Real IdealRealGasMixtureFluidProperties::prop##_from_T_v( \ 158 Real T, Real v, const std::vector<Real> & x) const \ 160 const Real x_primary = primaryMassFraction(x); \ 161 Real M_primary = _fp_primary->molarMass(); \ 163 Real sum = x_primary / M_primary; \ 164 for (unsigned int i = 0; i < _n_secondary_vapors; i++) \ 165 sum += x[i] / _fp_secondary[i]->molarMass(); \ 166 const Real M_star = 1. / sum; \ 168 const Real vp = v / x_primary; \ 169 const Real ep = _fp_primary->e_from_T_v(T, vp); \ 170 const Real yp = _fp_primary->prop##_from_v_e(vp, ep); \ 171 Real y = x_primary * M_star / M_primary * yp; \ 173 for (unsigned int i = 0; i < _n_secondary_vapors; i++) \ 175 const Real vi = v / x[i]; \ 176 const Real ei = _fp_secondary[i]->e_from_T_v(T, vp); \ 177 const Real Mi = _fp_secondary[i]->molarMass(); \ 178 const Real yi = _fp_secondary[i]->prop##_from_v_e(vi, ei); \ 179 y += x[i] * M_star / Mi * yi; \ 185 void IdealRealGasMixtureFluidProperties::prop##_from_T_v(Real T, \ 187 const std::vector<Real> & x, \ 191 std::vector<Real> & dy_dx) const \ 193 const Real x_primary = primaryMassFraction(x); \ 194 Real M_primary = _fp_primary->molarMass(); \ 196 Real sum = x_primary / M_primary; \ 197 for (unsigned int i = 0; i < _n_secondary_vapors; i++) \ 198 sum += x[i] / _fp_secondary[i]->molarMass(); \ 199 const Real M_star = 1. / sum; \ 201 const Real vp = v / x_primary; \ 202 const Real ep = _fp_primary->e_from_T_v(T, vp); \ 203 const Real yp = _fp_primary->prop##_from_v_e(vp, ep); \ 204 y = x_primary * M_star / M_primary * yp; \ 206 imperfectJacobianMessage("The temperature and specific volume derivatives in the following " \ 207 "function are currently neglected:\n\n", \ 208 __PRETTY_FUNCTION__); \ 213 dy_dx.resize(_n_secondary_vapors); \ 214 for (unsigned int i = 0; i < _n_secondary_vapors; i++) \ 216 const Real vi = v / x[i]; \ 217 const Real ei = _fp_secondary[i]->e_from_T_v(T, vi); \ 218 const Real Mi = _fp_secondary[i]->molarMass(); \ 219 const Real yi = _fp_secondary[i]->prop##_from_v_e(vi, ei); \ 220 y += x[i] * M_star / Mi * yi; \ 221 dy_dx[i] = -M_star / M_primary * yp - \ 222 x_primary * (1 / Mi - 1 / M_primary) * M_star * M_star / M_primary * yp + \ 224 sum_yj += x[i] * yi / Mi; \ 227 for (unsigned int i = 0; i < _n_secondary_vapors; i++) \ 229 const Real Mi = _fp_secondary[i]->molarMass(); \ 230 dy_dx[i] += -M_star * M_star * (1 / Mi - 1 / M_primary) * sum_yj; \ 238 define_transport_prop_from_T_v(
mu)
239 define_transport_prop_from_T_v(
k)
241 define_from_p_T_using_T_v(e)
242 define_from_p_T_using_T_v(s)
243 define_from_p_T_using_T_v(
c)
244 define_from_p_T_using_T_v(
cp)
245 define_from_p_T_using_T_v(
cv)
246 define_from_p_T_using_T_v(
mu)
247 define_from_p_T_using_T_v(
k)
249 define_from_v_e_using_T_v(p)
250 define_from_v_e_using_T_v(
c)
261 "fp_primary",
"Name of fluid properties user object for primary vapor component");
263 "fp_secondary",
"Name of fluid properties user object(s) for secondary vapor component(s)");
264 params.
addParam<
Real>(
"_T_mix_max", 1300.,
"Maximum temperature of the mixture");
274 _fp_secondary_names(getParam<
std::vector<UserObjectName>>(
"fp_secondary")),
275 _n_secondary_vapors(_fp_secondary_names.size()),
276 _T_mix_max(getParam<
Real>(
"_T_mix_max"))
292 mooseAssert(i < getNumberOfSecondaryVapors(),
"Requested secondary index too high.");
297 IdealRealGasMixtureFluidProperties::T_from_v_e(Real
v, Real e,
const std::vector<Real> &
x)
const 304 Real lower_temperature, upper_temperature;
308 lower_temperature =
_fp_primary->T_from_v_e(v_primary, e_sat_primary);
311 lower_temperature =
_fp_primary->T_from_v_e(v_primary, ec);
316 auto energy_diff = [&
v, &e, &
x,
this](
Real T) {
return this->e_from_T_v(T,
v,
x) - e; };
323 IdealRealGasMixtureFluidProperties::T_from_v_e(Real
v,
325 const std::vector<Real> &
x,
329 std::vector<Real> & dT_dx)
const 331 T = T_from_v_e(
v, e,
x);
333 Real e_unused, de_dT_v, de_dv_T;
334 std::vector<Real> de_dx_Tv;
335 e_from_T_v(T,
v,
x, e_unused, de_dT_v, de_dv_T, de_dx_Tv);
337 dT_dv = -de_dv_T / de_dT_v;
338 dT_de = 1.0 / de_dT_v;
341 dT_dx[i] = -de_dx_Tv[i] / de_dT_v;
345 IdealRealGasMixtureFluidProperties::rho_from_p_T(Real p, Real T,
const std::vector<Real> &
x)
const 347 return 1.0 / v_from_p_T(
p, T,
x);
351 IdealRealGasMixtureFluidProperties::rho_from_p_T(Real p,
353 const std::vector<Real> &
x,
357 std::vector<Real> & drho_dx)
const 359 Real v, dv_dp, dv_dT;
360 std::vector<Real> dv_dx;
361 v_from_p_T(
p, T,
x,
v, dv_dp, dv_dT, dv_dx);
364 const Real drho_dv = -1.0 / (
v *
v);
365 drho_dp = drho_dv * dv_dp;
366 drho_dT = drho_dv * dv_dT;
369 drho_dx[i] = drho_dv * dv_dx[i];
373 IdealRealGasMixtureFluidProperties::v_from_p_T(Real p, Real T,
const std::vector<Real> &
x)
const 378 Real sum = x_primary / M_primary;
381 Real M_star = 1. / sum;
387 Real v_spndl, e_spndl;
393 Real lower_spec_volume = v_spndl * x_primary;
394 Real upper_spec_volume = v_ideal;
397 Real p_max = p_from_T_v(T, lower_spec_volume,
x);
398 if (
p > p_max || upper_spec_volume < lower_spec_volume)
402 auto pressure_diff = [&T, &
p, &
x,
this](
Real v) {
return this->p_from_T_v(T,
v,
x) -
p; };
409 IdealRealGasMixtureFluidProperties::v_from_p_T(Real p,
411 const std::vector<Real> &
x,
415 std::vector<Real> & dv_dx)
const 417 v = v_from_p_T(
p, T,
x);
419 Real p_unused, dp_dT, dp_dv;
420 std::vector<Real> dp_dx;
421 p_from_T_v(T,
v,
x, p_unused, dp_dT, dp_dv, dp_dx);
424 dv_dT = -dp_dT / dp_dv;
427 dv_dx[i] = -dp_dx[i] / dp_dv;
431 IdealRealGasMixtureFluidProperties::e_from_p_rho(Real p,
433 const std::vector<Real> &
x)
const 438 return e_from_T_v(T,
v,
x);
442 IdealRealGasMixtureFluidProperties::e_from_p_rho(Real p,
444 const std::vector<Real> &
x,
448 std::vector<Real> & de_dx)
const 452 Real p_, dp_dT, dp_dv, de_dT, de_dv;
453 std::vector<Real> dp_dx_Tv;
454 std::vector<Real> de_dx_Tv;
456 p_from_T_v(T,
v,
x, p_, dp_dT, dp_dv, dp_dx_Tv);
457 e_from_T_v(T,
v,
x, e, de_dT, de_dv, de_dx_Tv);
459 de_dp = de_dT / dp_dT;
460 de_drho = (-
v *
v) * (de_dv - de_dT * dp_dv / dp_dT);
465 de_dx[i] = de_dx_Tv[i] - de_dT * dp_dx_Tv[i] / dp_dT;
470 IdealRealGasMixtureFluidProperties::T_from_p_v(Real p, Real
v,
const std::vector<Real> &
x)
const 477 Real lower_temperature, upper_temperature;
481 lower_temperature =
_fp_primary->T_from_v_e(v_primary, e_sat_primary);
484 lower_temperature =
_fp_primary->T_from_v_e(v_primary, ec);
489 auto pressure_diff = [&
p, &
v, &
x,
this](
Real T) {
return this->p_from_T_v(T,
v,
x) -
p; };
496 IdealRealGasMixtureFluidProperties::T_from_p_v(Real p,
498 const std::vector<Real> &
x,
502 std::vector<Real> & dT_dx)
const 504 T = T_from_p_v(
p,
v,
x);
507 Real p_unused, dp_dT_v, dp_dv_T;
508 std::vector<Real> dp_dx_Tv;
509 p_from_T_v(T,
v,
x, p_unused, dp_dT_v, dp_dv_T, dp_dx_Tv);
512 dT_dp = 1. / dp_dT_v;
513 dT_dv = -dp_dv_T / dp_dT_v;
517 dT_dx[i] = -dp_dx_Tv[i] / dp_dT_v;
521 IdealRealGasMixtureFluidProperties::p_from_T_v(Real T, Real
v,
const std::vector<Real> &
x)
const 533 IdealRealGasMixtureFluidProperties::p_from_T_v(Real T,
535 const std::vector<Real> &
x,
539 std::vector<Real> & dp_dx)
const 543 Real p_primary, dp_dT_primary, dp_dv_primary;
544 _fp_primary->p_from_T_v(T,
v / x_primary, p_primary, dp_dT_primary, dp_dv_primary);
546 dp_dT = dp_dT_primary;
547 dp_dv = dp_dv_primary / x_primary;
550 Real p_sec, dp_dT_sec, dxj_dxi;
554 _fp_secondary[i]->p_from_T_v(T,
v /
x[i], p_sec, dp_dT_sec, dp_dv_sec[i]);
557 dp_dv += dp_dv_sec[i] /
x[i];
564 dp_dx[i] = -dp_dv_sec[i] *
v / (
x[i] *
x[i]);
575 "The mass fraction derivatives in the following " 576 "function have not been tested for mixtures of 3 or more components:\n\n",
577 __PRETTY_FUNCTION__);
579 dp_dx[i] += -dp_dv_sec[
j] *
v / (
x[
j] *
x[
j]) * dxj_dxi;
581 dp_dx[i] += -dp_dv_primary *
v / (x_primary * x_primary) * (-x_primary / (1. -
x[i]));
586 IdealRealGasMixtureFluidProperties::c_from_T_v(Real T, Real
v,
const std::vector<Real> &
x)
const 588 Real p, dp_dT, dp_dv;
589 std::vector<Real> dp_dx;
590 p_from_T_v(T,
v,
x,
p, dp_dT, dp_dv, dp_dx);
592 Real s, ds_dT, ds_dv;
593 std::vector<Real> ds_dx;
594 s_from_T_v(T,
v,
x, s, ds_dT, ds_dv, ds_dx);
596 const Real dp_dv_s = dp_dv - dp_dT * ds_dv / ds_dT;
599 mooseWarning(
"c_from_T_v(): dp_dv_s = ", dp_dv_s,
". Should be negative.");
600 return v * std::sqrt(-dp_dv_s);
604 IdealRealGasMixtureFluidProperties::c_from_T_v(Real T,
606 const std::vector<Real> &
x,
610 std::vector<Real> & dc_dx)
const 612 c = c_from_T_v(T,
v,
x);
616 const Real dT = 1.e-6;
617 const Real T_perturbed = T + dT;
618 Real c_perturbed = c_from_T_v(T_perturbed,
v,
x);
619 dc_dT = (c_perturbed -
c) / dT;
621 const Real dv =
v * 1.e-6;
622 const Real v_perturbed =
v + dv;
623 c_perturbed = c_from_T_v(T, v_perturbed,
x);
624 dc_dv = (c_perturbed -
c) / dv;
629 std::vector<Real> x_perturbed(
x);
630 const Real dx_i = 1e-6;
635 x[
j] * (1.0 - (
x[i] + dx_i)) / (1.0 -
x[i]);
637 x_perturbed[i] += dx_i;
638 c_perturbed = c_from_T_v(T,
v, x_perturbed);
639 dc_dx[i] = ((c_perturbed -
c) / dx_i);
644 IdealRealGasMixtureFluidProperties::cp_from_T_v(Real T, Real
v,
const std::vector<Real> &
x)
const 648 Real p, dp_dT, dp_dv;
649 std::vector<Real> dp_dx;
650 p_from_T_v(T,
v,
x,
p, dp_dT, dp_dv, dp_dx);
652 Real h, dh_dT, dh_dv;
653 _fp_primary->h_from_T_v(T,
v / x_primary, h, dh_dT, dh_dv);
654 const Real cp_primary = dh_dT - dh_dv * dp_dT / dp_dv;
655 Real cp = x_primary * cp_primary;
660 const Real cp_sec = dh_dT - dh_dv * dp_dT / dp_dv;
668 IdealRealGasMixtureFluidProperties::cp_from_T_v(Real T,
670 const std::vector<Real> &
x,
674 std::vector<Real> & dcp_dx)
const 678 Real p, dp_dT, dp_dv;
679 std::vector<Real> dp_dx;
680 p_from_T_v(T,
v,
x,
p, dp_dT, dp_dv, dp_dx);
682 Real h, dh_dT, dh_dv;
683 _fp_primary->h_from_T_v(T,
v / x_primary, h, dh_dT, dh_dv);
684 const Real cp_primary = dh_dT - dh_dv * dp_dT / dp_dv;
685 cp = x_primary * cp_primary;
690 "function are currently neglected:\n\n",
691 __PRETTY_FUNCTION__);
699 const Real cp_sec = dh_dT - dh_dv * dp_dT / dp_dv;
701 dcp_dx[i] = cp_sec - cp_primary;
706 IdealRealGasMixtureFluidProperties::cv_from_T_v(Real T, Real
v,
const std::vector<Real> &
x)
const 718 IdealRealGasMixtureFluidProperties::cv_from_T_v(Real T,
720 const std::vector<Real> &
x,
724 std::vector<Real> & dcv_dx)
const 728 cv = x_primary * cv_primary;
733 "function are currently neglected:\n\n",
734 __PRETTY_FUNCTION__);
743 dcv_dx[i] = cv_sec - cv_primary;
750 const std::vector<Real> &
x)
const 769 Real pp_sat_secondary =
p - pp_sat;
773 v_secondary =
_fp_secondary[0]->v_from_p_T(pp_sat_secondary, T);
781 x_sec[i] =
x[i] / (1. - x_primary);
784 Real M_star = 1. / sum;
785 v_secondary =
R_molar * T / (M_star * pp_sat_secondary);
787 double f = 1., df_dvs, pp_sec, p_sec, dp_dT_sec, dp_dv_sec, dp_dv;
788 double tol_p = 1.e-8;
789 while (std::fabs(
f / pp_sat_secondary) > tol_p)
795 _fp_secondary[i]->p_from_T_v(T, v_secondary / x_sec[i], p_sec, dp_dT_sec, dp_dv_sec);
797 dp_dv += dp_dv_sec / x_sec[i];
799 f = pp_sec - pp_sat_secondary;
801 v_secondary -=
f / df_dvs;
807 xs = v_secondary / (v_primary + v_secondary);
virtual const SinglePhaseFluidProperties & getSecondaryFluidProperties(unsigned int i=0) const override
Gets a secondary component single-phase fluid properties.
Base class for fluid properties of vapor mixtures.
static const std::string cv
virtual Real molarMass() const
Molar mass [kg/mol].
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.
Real getNaN() const
Throws an error or returns a NaN with or without a warning, with a default message.
void imperfectJacobianMessage(Args... args) const
const SinglePhaseFluidProperties *const _fp_primary
Primary vapor fluid properties.
void mooseWarning(Args &&... args) const
static InputParameters validParams()
const Real _T_mix_max
maximum temperature of all components
virtual Real criticalInternalEnergy() const
Critical specific internal energy.
virtual const SinglePhaseFluidProperties & getPrimaryFluidProperties() const override
Gets the primary component single-phase fluid properties.
static const std::string cp
define_mass_specific_prop_from_T_v(e)
virtual Real criticalTemperature() const
Critical temperature.
const std::vector< double > x
Real f(Real x)
Test function for Brents method.
static InputParameters validParams()
static const std::string mu
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.
Common class for single phase fluid properties.
virtual void v_e_spndl_from_T(Real T, Real &v, Real &e) const
Specific internal energy from temperature and specific volume.
static constexpr const Real R_molar
molar (or universal) gas constant
virtual Real e_spndl_from_v(Real v) const
Specific internal energy from temperature and specific volume.
const std::vector< UserObjectName > _fp_secondary_names
Names of secondary vapor fluid properties.
virtual Real criticalDensity() const
Critical density.
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
static const std::string v
Class for fluid properties of an arbitrary vapor mixture.
Real primaryMassFraction(const std::vector< Real > &x) const
Computes the mass fraction of the primary vapor given mass fractions of the secondary vapors...
const unsigned int _n_secondary_vapors
Number of secondary vapors.
static InputParameters validParams()
static const std::complex< double > j(0, 1)
Complex number "j" (also known as "i")
IdealRealGasMixtureFluidProperties(const InputParameters ¶meters)
Interface class for producing errors, warnings, or just quiet NaNs.
std::vector< const SinglePhaseFluidProperties * > _fp_secondary
Secondary vapor fluid properties.
registerMooseObject("FluidPropertiesApp", IdealRealGasMixtureFluidProperties)
static const std::string k
void bracket(std::function< Real(Real)> const &f, Real &x1, Real &x2)
Function to bracket a root of a given function.