Real IdealRealGasMixtureFluidProperties::v_from_p_T(Real p, Real T, const std::vector<Real> & x) const { const Real x_primary = primaryMassFraction(x); Real M_primary = _fp_primary->molarMass(); Real sum = x_primary / M_primary; for (unsigned int i = 0; i < _n_secondary_vapors; i++) sum += x[i] / _fp_secondary[i]->molarMass(); Real M_star = 1. / sum; Real v_ideal = R_molar * T / (M_star * p); // check range of validity for primary (condensable) component static const Real Tc = _fp_primary->criticalTemperature(); static const Real vc = 1. / _fp_primary->criticalDensity(); Real v_spndl, e_spndl; if (T < Tc) _fp_primary->v_e_spndl_from_T(T, v_spndl, e_spndl); else v_spndl = vc; Real lower_spec_volume = v_spndl * x_primary; Real upper_spec_volume = v_ideal; // p*v/(RT) <= 1 // Initial estimate of a bracketing interval for the temperature Real p_max = p_from_T_v(T, lower_spec_volume, x); if (p > p_max || upper_spec_volume < lower_spec_volume) return getNaN(); // Use BrentsMethod to find temperature auto pressure_diff = [&T, &p, &x, this](Real v) { return this->p_from_T_v(T, v, x) - p; }; BrentsMethod::bracket(pressure_diff, lower_spec_volume, upper_spec_volume); Real v = BrentsMethod::root(pressure_diff, lower_spec_volume, upper_spec_volume); return v; }
StackSegment::StackSegment() :min(getNaN()) ,max(getNaN()) { }
Real IdealRealGasMixtureFluidProperties::xs_prim_from_p_T(Real p, Real T, const std::vector<Real> & x) const { Real T_c = _fp_primary->criticalTemperature(); Real xs; if (T > T_c) // return 1. to indicate that no water would condense for // given (p,T) xs = 1.; else { Real pp_sat = _fp_primary->pp_sat_from_p_T(p, T); if (pp_sat < 0.) { // return 1. to indicate that no water would condense for // given (p,T) xs = 1.; return xs; } Real v_primary = _fp_primary->v_from_p_T(pp_sat, T); Real pp_sat_secondary = p - pp_sat; Real v_secondary; if (_n_secondary_vapors == 1) v_secondary = _fp_secondary[0]->v_from_p_T(pp_sat_secondary, T); else { std::vector<Real> x_sec(_n_secondary_vapors); const Real x_primary = primaryMassFraction(x); Real sum = 0.; for (unsigned int i = 0; i < _n_secondary_vapors; i++) { x_sec[i] = x[i] / (1. - x_primary); sum += x_sec[i] / _fp_secondary[i]->molarMass(); } Real M_star = 1. / sum; v_secondary = R_molar * T / (M_star * pp_sat_secondary); int it = 0; double f = 1., df_dvs, pp_sec, p_sec, dp_dT_sec, dp_dv_sec, dp_dT, dp_dv; double tol_p = 1.e-8; while (std::fabs(f / pp_sat_secondary) > tol_p) { pp_sec = 0.; dp_dT = 0.; dp_dv = 0.; for (unsigned int i = 0; i < _n_secondary_vapors; i++) { _fp_secondary[i]->p_from_T_v(T, v_secondary / x_sec[i], p_sec, dp_dT_sec, dp_dv_sec); pp_sec += p_sec; dp_dT += dp_dT_sec; dp_dv += dp_dv_sec / x_sec[i]; } f = pp_sec - pp_sat_secondary; df_dvs = dp_dv; v_secondary -= f / df_dvs; if (it++ > 15) return getNaN(); } } xs = v_secondary / (v_primary + v_secondary); } return xs; }