20 double call(
double rhomolar_liq) {
23 std::cout <<
format(
"inner p: %0.16Lg; res: %0.16Lg", calc_p, calc_p - desired_p) << std::endl;
24 return calc_p - desired_p;
40 double call(
double rhomolar_vap) {
48 std::cout <<
format(
"outer p: %0.16Lg", p) << std::endl;
49 inner_resid inner(HEOS, T, p);
50 rhomolar_liq =
Brent(inner, rhomolar_crit * 1.5, rhomolar_crit * (1 + 1e-8), LDBL_EPSILON, 1e-10, 100);
54 throw ValueError(
"Wrong input for outer_resid");
69 outer_resid resid(HEOS,
iT, y);
73 Brent(&resid, rhomolar_crit * (1 - 1e-8), rhomolar_crit * 0.5,
DBL_EPSILON, 1e-9, 20);
86 : HEOS(&HEOS), T(T), rhomolar_liq(rhomolar_liq_guess), rhomolar_vap(rhomolar_vap_guess) {};
87 double call(
double p) {
89 HEOS->
SatL->update_TP_guessrho(T, p, rhomolar_liq);
90 HEOS->
SatV->update_TP_guessrho(T, p, rhomolar_vap);
100 solver_resid resid(HEOS, T, options.
rhoL, options.
rhoV);
103 throw ValueError(
format(
"options.p is not valid in saturation_T_pure_1D_P for T = %Lg", T));
106 throw ValueError(
format(
"options.rhoL is not valid in saturation_T_pure_1D_P for T = %Lg", T));
109 throw ValueError(
format(
"options.rhoV is not valid in saturation_T_pure_1D_P for T = %Lg", T));
113 Secant(resid, options.
p, options.
p * 1.1, 1e-10, 100);
117 Brent(resid, pmin, pmax, LDBL_EPSILON, 1e-8, 100);
131 : HEOS(&HEOS), p(p), rhomolar_liq(rhomolar_liq_guess), rhomolar_vap(rhomolar_vap_guess) {};
132 double call(
double T) {
134 HEOS->
SatL->update_TP_guessrho(T, p, rhomolar_liq);
135 HEOS->
SatV->update_TP_guessrho(T, p, rhomolar_vap);
145 solver_resid resid(HEOS, p, options.
rhoL, options.
rhoV);
148 throw ValueError(
"options.T is not valid in saturation_P_pure_1D_T");
151 throw ValueError(
"options.rhoL is not valid in saturation_P_pure_1D_T");
154 throw ValueError(
"options.rhoV is not valid in saturation_P_pure_1D_T");
159 Brent(resid, Tmin, Tmax, LDBL_EPSILON, 1e-11, 100);
172 std::vector<CoolPropDbl> negativer(3, _HUGE), v;
173 std::vector<std::vector<CoolPropDbl>> J(3, std::vector<CoolPropDbl>(3, _HUGE));
178 shared_ptr<HelmholtzEOSMixtureBackend> SatL = HEOS.
SatL, SatV = HEOS.
SatV;
181 CoolPropDbl deltaL = 0, deltaV = 0, tau = 0, error;
182 int iter = 0, specified_parameter;
191 T = HEOS.
get_components()[0].ancillaries.pL.invert(specified_value);
193 throw ValueError(
"Unable to invert ancillary equation");
201 throw ValueError(
"Unable to invert ancillary equation for hL");
210 this->component = &component;
213 double call(
double T) {
223 double Tmin = Tmin_satL;
230 double hTmin = HEOS_copy->hmolar();
232 double hTmax = HEOS_copy->hmolar();
233 T = (Tmax - Tmin) / (hTmax - hTmin) * (HEOS.
hmolar() - hTmin) + Tmin;
241 T = std::max(0.99 * crit.
T, crit.
T - 0.1);
249 T = anc.
invert(specified_value - hs_anchor.
smolar, Tmin, Tmax);
252 T = anc.
invert(specified_value - hs_anchor.
smolar, Tmin - 3, Tmax + 3);
256 if (std::abs(specified_value - hs_anchor.
smolar) < std::abs(vmax)) {
259 throw ValueError(
format(
"Unable to invert ancillary equation for sL for value %Lg with Tminval %g and Tmaxval %g ",
260 specified_value - hs_anchor.
smolar, vmin, vmax));
274 this->component = &component;
277 double call(
double T) {
284 Residual resid(component, HEOS.
smolar());
289 double Tmin = Tmin_satL;
296 if (std::abs(specified_value - hs_anchor.
smolar) < std::abs(vmax)) {
297 T = std::max(0.99 * crit.
T, crit.
T - 0.1);
301 double sTmin = HEOS_copy->smolar();
303 double sTmax = HEOS_copy->smolar();
304 T = (Tmax - Tmin) / (sTmax - sTmin) * (HEOS.
smolar() - sTmin) + Tmin;
324 double rhoL_updated = rhoL - (SatL->p() - SatV->p()) / SatL->first_partial_deriv(
iP,
iDmolar,
iT);
327 if (rhoL_updated > rhoV) {
359 CoolPropDbl d2alphar_ddelta_dtauL = SatL->d2alphar_dDelta_dTau();
360 CoolPropDbl d2alphar_ddelta_dtauV = SatV->d2alphar_dDelta_dTau();
361 CoolPropDbl dalphar_ddeltaL = SatL->dalphar_dDelta();
362 CoolPropDbl dalphar_ddeltaV = SatV->dalphar_dDelta();
363 CoolPropDbl d2alphar_ddelta2L = SatL->d2alphar_dDelta2();
364 CoolPropDbl d2alphar_ddelta2V = SatV->d2alphar_dDelta2();
367 negativer[0] = -(deltaV * (1 + deltaV * dalphar_ddeltaV) - deltaL * (1 + deltaL * dalphar_ddeltaL));
369 negativer[1] = -(deltaV * dalphar_ddeltaV + alpharV + log(deltaV) - deltaL * dalphar_ddeltaL - alpharL - log(deltaL));
371 case saturation_PHSU_pure_options::IMPOSED_PL:
373 negativer[2] = -(pL / specified_value - 1);
375 case saturation_PHSU_pure_options::IMPOSED_PV:
377 negativer[2] = -(pV / specified_value - 1);
379 case saturation_PHSU_pure_options::IMPOSED_HL:
381 negativer[2] = -(hL - specified_value);
383 case saturation_PHSU_pure_options::IMPOSED_HV:
385 negativer[2] = -(hV - specified_value);
387 case saturation_PHSU_pure_options::IMPOSED_SL:
389 negativer[2] = -(sL - specified_value);
391 case saturation_PHSU_pure_options::IMPOSED_SV:
393 negativer[2] = -(sV - specified_value);
400 J[0][0] = pow(deltaV, 2) * d2alphar_ddelta_dtauV - pow(deltaL, 2) * d2alphar_ddelta_dtauL;
402 J[1][0] = deltaV * d2alphar_ddelta_dtauV + dalphar_dtauV - deltaL * d2alphar_ddelta_dtauL - dalphar_dtauL;
406 J[0][1] = -deltaL - 2 * pow(deltaL, 2) * dalphar_ddeltaL - pow(deltaL, 3) * d2alphar_ddelta2L;
408 J[1][1] = -pow(deltaL, 2) * d2alphar_ddelta2L - 2 * deltaL * dalphar_ddeltaL - 1;
411 J[0][1] = -1 - 2 * deltaL * dalphar_ddeltaL - pow(deltaL, 2) * d2alphar_ddelta2L;
413 J[1][1] = -1 / deltaL - 2 * dalphar_ddeltaL - deltaL * d2alphar_ddelta2L;
418 J[0][2] = deltaV + 2 * pow(deltaV, 2) * dalphar_ddeltaV + pow(deltaV, 3) * d2alphar_ddelta2V;
420 J[1][2] = 1 + 2 * deltaV * dalphar_ddeltaV + 1 + pow(deltaV, 2) * d2alphar_ddelta2V;
423 J[0][2] = 1 + 2 * deltaV * dalphar_ddeltaV + pow(deltaV, 2) * d2alphar_ddelta2V;
425 J[1][2] = deltaV * d2alphar_ddelta2V + 2 * dalphar_ddeltaV + 1 / deltaV;
430 case saturation_PHSU_pure_options::IMPOSED_PL:
432 J[2][0] = SatL->first_partial_deriv(
iP,
iTau,
iDelta) / specified_value;
435 J[2][1] = deltaL * SatL->first_partial_deriv(
iP,
iDelta,
iTau) / specified_value;
438 J[2][1] = SatL->first_partial_deriv(
iP,
iDelta,
iTau) / specified_value;
444 case saturation_PHSU_pure_options::IMPOSED_PV:
446 J[2][0] = SatV->first_partial_deriv(
iP,
iTau,
iDelta) / specified_value;
451 J[2][2] = deltaV * SatV->first_partial_deriv(
iP,
iDelta,
iTau) / specified_value;
454 J[2][2] = SatV->first_partial_deriv(
iP,
iDelta,
iTau) / specified_value;
458 case saturation_PHSU_pure_options::IMPOSED_HL:
470 case saturation_PHSU_pure_options::IMPOSED_HV:
482 case saturation_PHSU_pure_options::IMPOSED_SL:
494 case saturation_PHSU_pure_options::IMPOSED_SV:
515 double tau0 = tau, deltaL0 = deltaL, deltaV0 = deltaV;
516 for (
double omega_local = 1.0; omega_local > 0.1; omega_local /= 1.1) {
517 tau = tau0 + omega_local * options.
omega * v[0];
519 deltaL = exp(log(deltaL0) + omega_local * options.
omega * v[1]);
520 deltaV = exp(log(deltaV0) + omega_local * options.
omega * v[2]);
522 deltaL = deltaL0 + omega_local * options.
omega * v[1];
523 deltaV = deltaV0 + omega_local * options.
omega * v[2];
525 if (tau > 1 && deltaL > deltaV) {
537 error = sqrt(pow(negativer[0], 2) + pow(negativer[1], 2) + pow(negativer[2], 2));
553 throw SolutionError(
format(
"saturation_PHSU_pure solver did not converge after 50 iterations for %s=%Lg current error is %Lg",
554 info.c_str(), specified_value, error));
556 }
while (error > 1e-9);
562 SatL->unspecify_phase();
563 SatV->unspecify_phase();
566 negativer[0] = -(deltaV * (1 + deltaV * SatV->dalphar_dDelta()) - deltaL * (1 + deltaL * SatL->dalphar_dDelta()));
567 negativer[1] = -(deltaV * SatV->dalphar_dDelta() + SatV->alphar() + log(deltaV) - deltaL * SatL->dalphar_dDelta() - SatL->alphar() - log(deltaL));
569 case saturation_PHSU_pure_options::IMPOSED_PL:
571 negativer[2] = -(SatL->p() / specified_value - 1);
573 case saturation_PHSU_pure_options::IMPOSED_PV:
575 negativer[2] = -(SatV->p() / specified_value - 1);
577 case saturation_PHSU_pure_options::IMPOSED_HL:
579 negativer[2] = -(SatL->hmolar() - specified_value);
581 case saturation_PHSU_pure_options::IMPOSED_HV:
583 negativer[2] = -(SatV->hmolar() - specified_value);
585 case saturation_PHSU_pure_options::IMPOSED_SL:
587 negativer[2] = -(SatL->smolar() - specified_value);
589 case saturation_PHSU_pure_options::IMPOSED_SV:
591 negativer[2] = -(SatV->smolar() - specified_value);
596 error = sqrt(pow(negativer[0], 2) + pow(negativer[1], 2) + pow(negativer[2], 2));
601 throw SolutionError(
format(
"saturation_PHSU_pure solver was good, but went bad. Current error is %Lg", error));
614 std::vector<CoolPropDbl> r(2, _HUGE), v;
615 std::vector<std::vector<CoolPropDbl>> J(2, std::vector<CoolPropDbl>(2, _HUGE));
619 shared_ptr<HelmholtzEOSMixtureBackend> SatL = HEOS.
SatL, SatV = HEOS.
SatV;
622 CoolPropDbl deltaL = 0, deltaV = 0, tau = 0, error, p_error;
627 if (options.
imposed_rho == saturation_D_pure_options::IMPOSED_RHOL) {
633 }
else if (options.
imposed_rho == saturation_D_pure_options::IMPOSED_RHOV) {
665 CoolPropDbl d2alphar_ddelta_dtauL = SatL->d2alphar_dDelta_dTau();
666 CoolPropDbl d2alphar_ddelta_dtauV = SatV->d2alphar_dDelta_dTau();
669 CoolPropDbl dalphar_ddeltaL = SatL->dalphar_dDelta();
670 CoolPropDbl dalphar_ddeltaV = SatV->dalphar_dDelta();
673 r[0] = -(deltaV * (1 + deltaV * dalphar_ddeltaV) - deltaL * (1 + deltaL * dalphar_ddeltaL));
675 r[1] = -(deltaV * dalphar_ddeltaV + alpharV + log(deltaV) - deltaL * dalphar_ddeltaL - alpharL - log(deltaL));
678 J[0][0] = pow(deltaV, 2) * d2alphar_ddelta_dtauV - pow(deltaL, 2) * d2alphar_ddelta_dtauL;
680 J[1][0] = deltaV * d2alphar_ddelta_dtauV + dalphar_dtauV - deltaL * d2alphar_ddelta_dtauL - dalphar_dtauL;
682 if (options.
imposed_rho == saturation_D_pure_options::IMPOSED_RHOL) {
683 CoolPropDbl d2alphar_ddelta2V = SatV->d2alphar_dDelta2();
685 J[0][1] = deltaV + 2 * pow(deltaV, 2) * dalphar_ddeltaV + pow(deltaV, 3) * d2alphar_ddelta2V;
686 J[1][1] = pow(deltaV, 2) * d2alphar_ddelta2V + 2 * deltaV * dalphar_ddeltaV + 1;
688 J[0][1] = 1 + 2 * deltaV * dalphar_ddeltaV + pow(deltaV, 2) * d2alphar_ddelta2V;
689 J[1][1] = deltaV * d2alphar_ddelta2V + 2 * dalphar_ddeltaV + 1 / deltaV;
691 }
else if (options.
imposed_rho == saturation_D_pure_options::IMPOSED_RHOV) {
692 CoolPropDbl d2alphar_ddelta2L = SatL->d2alphar_dDelta2();
694 J[0][1] = -deltaL - 2 * pow(deltaL, 2) * dalphar_ddeltaL - pow(deltaL, 3) * d2alphar_ddelta2L;
695 J[1][1] = -pow(deltaL, 2) * d2alphar_ddelta2L - 2 * deltaL * dalphar_ddeltaL - 1;
697 J[0][1] = -1 - 2 * deltaL * dalphar_ddeltaL - pow(deltaL, 2) * d2alphar_ddelta2L;
698 J[1][1] = -deltaL * d2alphar_ddelta2L - 2 * dalphar_ddeltaL - 1 / deltaL;
706 double omega = options.
omega;
708 if (options.
imposed_rho == saturation_D_pure_options::IMPOSED_RHOL) {
710 deltaV = exp(log(deltaV) + omega * v[1]);
712 if (deltaV + omega * v[1] <= 0) {
713 omega = 0.5 * deltaV / v[1];
715 if (tau + omega * v[0] <= 0) {
716 omega = 0.5 * tau / v[0];
718 deltaV += omega * v[1];
722 deltaL = exp(log(deltaL) + omega * v[1]);
724 if (deltaL + omega * v[1] <= 0) {
725 omega = 0.5 * deltaL / v[1];
727 if (tau + omega * v[0] <= 0) {
728 omega = 0.5 * tau / v[0];
730 deltaL += omega * v[1];
740 p_error = (pL - pV) / pL;
742 error = sqrt(pow(r[0], 2) + pow(r[1], 2));
749 format(
"saturation_D_pure solver did not converge after %d iterations with rho: %g mol/m^3", options.
max_iterations, rhomolar));
751 }
while (error > 1e-9);
753 if (std::abs(p_error) > p_error_limit) {
754 throw SolutionError(
format(
"saturation_D_pure solver abs error on p [%Lg] > limit [%Lg]", p_error, p_error_limit));
760 _options.
omega = 1.0;
770 options.
pL = _options.
pL;
771 options.
pV = _options.
pV;
774 options.
p = _options.
pL;
795 shared_ptr<HelmholtzEOSMixtureBackend> SatL = HEOS.
SatL, SatV = HEOS.
SatV;
797 CoolPropDbl rhoL = _HUGE, rhoV = _HUGE, JL, JV, KL, KV, dJL, dJV, dKL, dKV;
798 CoolPropDbl DELTA, deltaL = 0, deltaV = 0, error, PL, PV, stepL, stepV;
811 rhoL = HEOS.
get_components()[0].ancillaries.rhoL.evaluate(T - 0.1);
812 rhoV = HEOS.
get_components()[0].ancillaries.rhoV.evaluate(T - 0.1);
861 CoolPropDbl dalphar_ddeltaL = SatL->dalphar_dDelta();
862 CoolPropDbl dalphar_ddeltaV = SatV->dalphar_dDelta();
863 CoolPropDbl d2alphar_ddelta2L = SatL->d2alphar_dDelta2();
864 CoolPropDbl d2alphar_ddelta2V = SatV->d2alphar_dDelta2();
866 JL = deltaL * (1 + deltaL * dalphar_ddeltaL);
867 JV = deltaV * (1 + deltaV * dalphar_ddeltaV);
868 KL = deltaL * dalphar_ddeltaL + alpharL + log(deltaL);
869 KV = deltaV * dalphar_ddeltaV + alpharV + log(deltaV);
871 PL = R_u * reduce.
rhomolar * T * JL;
872 PV = R_u * reduce.
rhomolar * T * JV;
875 dJL = 1 + 2 * deltaL * dalphar_ddeltaL + deltaL * deltaL * d2alphar_ddelta2L;
876 dJV = 1 + 2 * deltaV * dalphar_ddeltaV + deltaV * deltaV * d2alphar_ddelta2V;
877 dKL = 2 * dalphar_ddeltaL + deltaL * d2alphar_ddelta2L + 1 / deltaL;
878 dKV = 2 * dalphar_ddeltaV + deltaV * d2alphar_ddelta2V + 1 / deltaV;
880 DELTA = dJV * dKL - dJL * dKV;
882 error = sqrt((KL - KV) * (KL - KV) + (JL - JV) * (JL - JV));
885 stepL = options.
omega / DELTA * ((KV - KL) * dJV - (JV - JL) * dKV);
886 stepV = options.
omega / DELTA * ((KV - KL) * dJL - (JV - JL) * dKL);
891 for (
double omega_local = 1.0; omega_local > 0.1; omega_local /= 1.1) {
892 deltaL = deltaL0 + omega_local * stepL;
893 deltaV = deltaV0 + omega_local * stepV;
895 if (deltaL > 1 && deltaV < 1 && deltaV > 0) {
906 }
while (error > 1e-10 && std::abs(stepL) > 10 *
DBL_EPSILON * std::abs(stepL) && std::abs(stepV) > 10 *
DBL_EPSILON * std::abs(stepV));
910 if (std::abs(p_error) > p_error_limit) {
915 throw SolutionError(
format(
"saturation_T_pure_Akasaka solver abs error on p [%g] > limit [%g]", std::abs(p_error), p_error_limit));
936 shared_ptr<HelmholtzEOSMixtureBackend> SatL = HEOS.
SatL, SatV = HEOS.
SatV;
938 CoolPropDbl rhoL = _HUGE, rhoV = _HUGE, error = 999, DeltavL, DeltavV, pL, pV, p, last_error;
939 int iter = 0, small_step_count = 0,
940 backwards_step_count = 0;
952 rhoL = HEOS.
get_components()[0].ancillaries.rhoL.evaluate(T - 0.1);
953 rhoV = HEOS.
get_components()[0].ancillaries.rhoV.evaluate(T - 0.1);
964 if ((rhoL < crit.rhomolar * 0.8 || rhoL > tripleL.
rhomolar * 1.2 || rhoV > crit.
rhomolar * 1.2 || rhoV < tripleV.
rhomolar * 0.8)
969 "[Maxwell] ancillaries correction T: %0.16Lg rhoL: %0.16Lg rhoV: %0.16Lg rhoc: %g rhoLtrip: %g rhoVtrip: %g\n", T, rhoL,
976 SatL->update_DmolarT_direct(rhoL, T);
979 rhoV = SatL->p() / (SatL->gas_constant() * T);
981 rhoV = p / (SatL->gas_constant() * T);
984 SatV->update_DmolarT_direct(rhoV, T);
986 SatL->update_DmolarT_direct(rhoL, T);
987 SatV->update_DmolarT_direct(rhoV, T);
990 std::cout <<
format(
"[Maxwell] ancillaries T: %0.16Lg rhoL: %0.16Lg rhoV: %0.16Lg pL: %g pV: %g\n", T, rhoL, rhoV, SatL->p(),
997 if (std::abs((SatL->p() - p) / p) > 0.1) {
998 for (
int iii = 0; iii < 6; ++iii) {
1003 CoolPropDbl deltarhoLHalley = -(2 * f * dpdrho) / (2 *
POW2(dpdrho) - f * d2pdrho2);
1004 rhoL += deltarhoLHalley;
1005 if (std::abs(deltarhoLHalley / rhoL) <
DBL_EPSILON) {
1008 SatL->update_DmolarT_direct(rhoL, T);
1012 SatL->update_DmolarT_direct(rhoL, T);
1013 SatV->update_DmolarT_direct(rhoV, T);
1018 if (std::abs((SatV->p() - p) / p) > 0.1) {
1020 rhoV = SatV->solver_rho_Tp(T, p, rhoV);
1035 SatL->update_DmolarT_direct(rhoL, T);
1036 SatV->update_DmolarT_direct(rhoV, T);
1038 std::cout <<
format(
"[Maxwell] starting T: %0.16Lg rhoL: %Lg rhoV: %Lg pL: %Lg pV: %g\n", T, rhoL, rhoV, SatL->p(), SatV->p());
1043 CoolPropDbl vL = 1 / SatL->rhomolar(), vV = 1 / SatV->rhomolar();
1051 CoolPropDbl helmholtzL = (SatL->calc_alpha0() + SatL->calc_alphar()) * RT;
1052 CoolPropDbl helmholtzV = (SatV->calc_alpha0() + SatV->calc_alphar()) * RT;
1055 CoolPropDbl pM = (helmholtzL - helmholtzV) / (vV - vL);
1059 CoolPropDbl B = alphaL * (pL - pV - alphaV * (vL - vV));
1063 CoolPropDbl sqrt_arg = std::abs(B * B / (4 * A * A) - C / A);
1067 if (std::abs(sqrt_arg) > 1e-10) {
1068 DeltavL = -0.5 * B / A +
sign((alphaL - alphaV) / alphaV) * sqrt(sqrt_arg);
1072 DeltavL = -0.5 * B / A +
sign((alphaL - alphaV) / alphaV) * sqrt(sqrt_arg * powerfactor) / sqrt(powerfactor);
1074 DeltavV = (pL - pV + alphaL * DeltavL) / alphaV;
1077 rhoL = 1 / (vL + DeltavL);
1078 rhoV = 1 / (vV + DeltavV);
1079 if (B * B / (4 * A * A) - C / A < -10 *
DBL_EPSILON) {
1085 SatL->update_DmolarT_direct(rhoL, T);
1086 SatV->update_DmolarT_direct(rhoV, T);
1089 error = std::abs((SatL->p() - SatV->p()) / SatL->p());
1092 std::cout <<
format(
"[Maxwell] rhoL: %0.16Lg rhoV: %0.16Lg error: %Lg dvL/vL: %Lg dvV/vV: %Lg pL: %Lg pV: %Lg\n", rhoL, rhoV, error,
1093 DeltavL / vL, DeltavV / vV, pL, pV);
1098 if (std::abs(DeltavL * rhoL) < 1e-13 || std::abs(DeltavV * rhoV) < 1e-13) {
1103 if (std::abs(error) > std::abs(last_error)) {
1104 backwards_step_count++;
1110 throw SolutionError(
format(
"Maxwell solver did not converge after 30 iterations; rhoL: %0.16Lg rhoV: %0.16Lg error: %Lg dvL/vL: %Lg "
1111 "dvV/vV: %Lg pL: %Lg pV: %Lg\n",
1112 rhoL, rhoV, error, DeltavL / vL, DeltavV / vV, pL, pV));
1114 }
while ((SatL->p() < 0) || (error > 1e-10 && small_step_count < 4 && backwards_step_count < 6));
1116 std::cout <<
format(
"[Maxwell] pL: %g pV: %g\n", SatL->p(), SatV->p());
1121 std::vector<CoolPropDbl>& x, std::vector<CoolPropDbl>& y) {
1122 for (
unsigned int i = 0; i < K.size(); i++) {
1123 double denominator = (1 - beta + beta * K[i]);
1124 x[i] = z[i] / denominator;
1125 y[i] = K[i] * z[i] / denominator;
1130 const std::vector<CoolPropDbl>& z, std::vector<CoolPropDbl>& K,
mixture_VLE_IO& options) {
1133 std::size_t N = z.size();
1134 std::vector<CoolPropDbl> ln_phi_liq, ln_phi_vap;
1135 ln_phi_liq.resize(N);
1136 ln_phi_vap.resize(N);
1138 std::vector<CoolPropDbl>&x = HEOS.
SatL->get_mole_fractions_ref(), &y = HEOS.
SatV->get_mole_fractions_ref();
1147 HEOS.
SatL->set_mole_fractions(x);
1148 HEOS.
SatV->set_mole_fractions(y);
1149 HEOS.
SatL->calc_reducing_state();
1150 HEOS.
SatV->calc_reducing_state();
1156 double summer_c = 0, v_SRK = 1 / rhomolar_liq;
1157 const std::vector<CoolPropFluid>& components = HEOS.
get_components();
1158 for (std::size_t i = 0; i < components.size(); ++i) {
1165 summer_c += z[i] * (0.40768 * R * Tc / pc * (0.29441 - pc / (rhomolarc * R * Tc)));
1167 rhomolar_liq = 1 / (v_SRK - summer_c);
1168 HEOS.
SatL->update_TP_guessrho(T, p, rhomolar_liq);
1169 HEOS.
SatV->update_TP_guessrho(T, p, rhomolar_vap);
1172 HEOS.
SatL->update_TP_guessrho(T, p, HEOS.
SatL->rhomolar());
1173 HEOS.
SatV->update_TP_guessrho(T, p, HEOS.
SatV->rhomolar());
1179 for (std::size_t i = 0; i < N; ++i) {
1193 K[i] = exp(ln_phi_liq[i] - ln_phi_vap[i]);
1195 f += z[i] * (K[i] - 1) / (1 - beta + beta * K[i]);
1197 double dfdK = K[i] * z[i] / pow(1 - beta + beta * K[i], (
int)2);
1198 df += dfdK * (deriv_liq - deriv_vap);
1201 if (std::abs(df) <= 1e-14) {
1202 if (std::abs(f) <= 1e-12)
1206 throw ValueError(
format(
"df very small (df = %g) in successive_substitution but f is not converged (f = %g > 1e-12).", df, f));
1216 if (std::abs(change) > 0.05 * p) {
1219 p += omega * change;
1225 HEOS.
SatL->set_mole_fractions(x);
1226 HEOS.
SatV->set_mole_fractions(y);
1230 throw ValueError(
format(
"saturation_p was unable to reach a solution within 50 iterations"));
1232 }
while (std::abs(f) > 1e-12 && iter < options.
Nstep_max);
1234 HEOS.
SatL->update_TP_guessrho(T, p, HEOS.
SatL->rhomolar());
1235 HEOS.
SatV->update_TP_guessrho(T, p, HEOS.
SatV->rhomolar());
1237 options.
p = HEOS.
SatL->p();
1238 options.
T = HEOS.
SatL->T();
1244void SaturationSolvers::newton_raphson_saturation::resize(std::size_t N) {
1249 if (imposed_variable == newton_raphson_saturation_options::RHOV_IMPOSED) {
1251 err_rel.resize(N + 1);
1252 J.resize(N + 1, N + 1);
1253 }
else if (imposed_variable == newton_raphson_saturation_options::P_IMPOSED || imposed_variable == newton_raphson_saturation_options::T_IMPOSED) {
1261void SaturationSolvers::newton_raphson_saturation::check_Jacobian() {
1263 HelmholtzEOSMixtureBackend &rSatL = *(HEOS->SatL.get()), &rSatV = *(HEOS->SatV.get());
1270 std::vector<CoolPropDbl> x0 = x;
1271 Eigen::VectorXd r0 = r;
1272 Eigen::MatrixXd J0 = J;
1278 double dT = 1e-3, T1 = T + dT, T2 = T - dT;
1280 this->rhomolar_liq = rhomolar_liq0;
1281 this->rhomolar_vap = rhomolar_vap0;
1283 Eigen::VectorXd r1 = r;
1285 this->rhomolar_liq = rhomolar_liq0;
1286 this->rhomolar_vap = rhomolar_vap0;
1288 Eigen::VectorXd r2 = r;
1290 Eigen::VectorXd diffn = (r1 - r2) / (2 * dT);
1291 std::cout <<
format(
"For T\n");
1299 this->rhomolar_liq = rhomolar_liq0 + drho;
1300 this->rhomolar_vap = rhomolar_vap0;
1302 Eigen::VectorXd rr1 = r;
1304 this->rhomolar_liq = rhomolar_liq0 - drho;
1305 this->rhomolar_vap = rhomolar_vap0;
1307 Eigen::VectorXd rr2 = r;
1309 Eigen::VectorXd diffn = (rr1 - rr2) / (2 * drho);
1310 std::cout <<
format(
"For rho\n");
1314 for (std::size_t i = 0; i < x.size() - 1; ++i) {
1319 this->x[x.size() - 1] -= dx;
1321 this->rhomolar_liq = rhomolar_liq0;
1322 this->rhomolar_vap = rhomolar_vap0;
1324 Eigen::VectorXd r1 = this->r;
1328 this->x[x.size() - 1] += dx;
1330 this->rhomolar_liq = rhomolar_liq0;
1331 this->rhomolar_vap = rhomolar_vap0;
1333 Eigen::VectorXd r2 = this->r;
1335 Eigen::VectorXd diffn = (r1 - r2) / (2 * dx);
1336 std::cout <<
format(
"For x%d N %d\n", i, N);
1341void SaturationSolvers::newton_raphson_saturation::call(HelmholtzEOSMixtureBackend& HEOS,
const std::vector<CoolPropDbl>& z,
1342 std::vector<CoolPropDbl>& z_incipient, newton_raphson_saturation_options& IO) {
1347 std::cout <<
" NRsat::call: p " << IO.p <<
" T " << IO.T <<
" dl " << IO.rhomolar_liq <<
" dv " << IO.rhomolar_vap << std::endl;
1353 this->bubble_point = IO.bubble_point;
1354 rhomolar_liq = IO.rhomolar_liq;
1355 rhomolar_vap = IO.rhomolar_vap;
1358 imposed_variable = IO.imposed_variable;
1383 Eigen::VectorXd v = J.colPivHouseholderQr().solve(-r);
1386 for (
unsigned int i = 0; i < N - 1; ++i) {
1387 err_rel[i] = v[i] / y[i];
1390 y[N - 1] = 1 - std::accumulate(y.begin(), y.end() - 1, 0.0);
1392 for (
unsigned int i = 0; i < N - 1; ++i) {
1393 err_rel[i] = v[i] / x[i];
1396 x[N - 1] = 1 - std::accumulate(x.begin(), x.end() - 1, 0.0);
1398 if (imposed_variable == newton_raphson_saturation_options::P_IMPOSED) {
1400 err_rel[N - 1] = v[N - 1] / T;
1401 }
else if (imposed_variable == newton_raphson_saturation_options::T_IMPOSED) {
1403 err_rel[N - 1] = v[N - 1] / p;
1404 }
else if (imposed_variable == newton_raphson_saturation_options::RHOV_IMPOSED) {
1406 err_rel[N - 1] = v[N - 1] / T;
1407 rhomolar_liq += v[N];
1408 err_rel[N] = v[N] / rhomolar_liq;
1410 throw ValueError(
"invalid imposed_variable");
1416 min_rel_change = err_rel.cwiseAbs().minCoeff();
1419 if (iter == IO.Nstep_max) {
1420 throw ValueError(
format(
"newton_raphson_saturation::call reached max number of iterations [%d]", IO.Nstep_max));
1422 }
while (this->error_rms > 1e-7 && min_rel_change > 1000 *
DBL_EPSILON && iter < IO.Nstep_max);
1429 IO.rhomolar_liq = rhomolar_liq;
1430 IO.rhomolar_vap = rhomolar_vap;
1431 const std::vector<CoolPropFluid>& fluidsL = HEOS.SatL->get_components();
1432 const std::vector<CoolPropFluid>& fluidsV = HEOS.SatV->get_components();
1433 if (!fluidsL.empty() && !fluidsV.empty()) {
1434 IO.hmolar_liq = HEOS.SatL->hmolar();
1435 IO.hmolar_vap = HEOS.SatV->hmolar();
1436 IO.smolar_liq = HEOS.SatL->smolar();
1437 IO.smolar_vap = HEOS.SatV->smolar();
1441void SaturationSolvers::newton_raphson_saturation::build_arrays() {
1443 HelmholtzEOSMixtureBackend &rSatL = *(HEOS->SatL.get()), &rSatV = *(HEOS->SatV.get());
1450 rSatV.set_mole_fractions(y);
1451 rSatL.set_mole_fractions(x);
1454 rSatL.set_mole_fractions(x);
1455 rSatV.set_mole_fractions(y);
1458 if (imposed_variable == newton_raphson_saturation_options::RHOV_IMPOSED) {
1461 }
else if (imposed_variable == newton_raphson_saturation_options::P_IMPOSED || imposed_variable == newton_raphson_saturation_options::T_IMPOSED) {
1462 rSatL.update_TP_guessrho(T, p, rhomolar_liq);
1463 rhomolar_liq = rSatL.rhomolar();
1464 rSatV.update_TP_guessrho(T, p, rhomolar_vap);
1465 rhomolar_vap = rSatV.rhomolar();
1467 throw ValueError(
"imposed variable not set for NR VLE");
1473 p = 0.5 * (p_liq + p_vap);
1481 if (imposed_variable == newton_raphson_saturation_options::RHOV_IMPOSED) {
1483 for (std::size_t i = 0; i < N; ++i) {
1487 r(i) = ln_f_liq - ln_f_vap;
1489 for (std::size_t j = 0; j < N - 1; ++j) {
1503 r(N) = p_liq - p_vap;
1504 for (std::size_t j = 0; j < N - 1; ++j) {
1509 J(N, N) = rSatL.first_partial_deriv(
iP,
iDmolar,
iT);
1510 }
else if (imposed_variable == newton_raphson_saturation_options::P_IMPOSED) {
1514 for (std::size_t i = 0; i < N; ++i) {
1518 r(i) = ln_f_liq - ln_f_vap;
1520 for (std::size_t j = 0; j < N - 1; ++j) {
1530 }
else if (imposed_variable == newton_raphson_saturation_options::T_IMPOSED) {
1534 for (std::size_t i = 0; i < N; ++i) {
1538 r(i) = ln_f_liq - ln_f_vap;
1540 for (std::size_t j = 0; j < N - 1; ++j) {
1554 error_rms = r.norm();
1559 for (std::size_t i = 0; i < N; ++i) {
1567 dTsat_dPsat = -dQ_dPsat / dQ_dTsat;
1568 dPsat_dTsat = -dQ_dTsat / dQ_dPsat;
1571void SaturationSolvers::newton_raphson_twophase::call(HelmholtzEOSMixtureBackend& HEOS, newton_raphson_twophase_options& IO) {
1575 std::cout <<
" NRsat::call: p" << IO.p <<
" T" << IO.T <<
" dl" << IO.rhomolar_liq <<
" dv" << IO.rhomolar_vap << std::endl;
1581 rhomolar_liq = IO.rhomolar_liq;
1582 rhomolar_vap = IO.rhomolar_vap;
1585 imposed_variable = IO.imposed_variable;
1594 r.resize(2 * N - 1);
1595 J.resize(2 * N - 1, 2 * N - 1);
1596 err_rel.resize(2 * N - 1);
1612 Eigen::VectorXd v = J.colPivHouseholderQr().solve(-r);
1614 for (
unsigned int i = 0; i < N - 1; ++i) {
1615 err_rel[i] = v[i] / x[i];
1617 err_rel[i + (N - 1)] = v[i + (N - 1)] / y[i];
1618 y[i] += v[i + (N - 1)];
1620 x[N - 1] = 1 - std::accumulate(x.begin(), x.end() - 1, 0.0);
1621 y[N - 1] = 1 - std::accumulate(y.begin(), y.end() - 1, 0.0);
1623 if (imposed_variable == newton_raphson_twophase_options::P_IMPOSED) {
1625 err_rel[2 * N - 2] = v[2 * N - 2] / T;
1626 }
else if (imposed_variable == newton_raphson_twophase_options::T_IMPOSED) {
1628 err_rel[2 * N - 2] = v[2 * N - 2] / p;
1630 throw ValueError(
"invalid imposed_variable");
1634 min_rel_change = err_rel.cwiseAbs().minCoeff();
1637 if (iter == IO.Nstep_max) {
1638 throw ValueError(
format(
"newton_raphson_saturation::call reached max number of iterations [%d]", IO.Nstep_max));
1640 }
while (this->error_rms > 1e-9 && min_rel_change > 1000 *
DBL_EPSILON && iter < IO.Nstep_max);
1647 IO.rhomolar_liq = rhomolar_liq;
1648 IO.rhomolar_vap = rhomolar_vap;
1649 IO.hmolar_liq = HEOS.SatL.get()->hmolar();
1650 IO.hmolar_vap = HEOS.SatV.get()->hmolar();
1651 IO.smolar_liq = HEOS.SatL.get()->smolar();
1652 IO.smolar_vap = HEOS.SatV.get()->smolar();
1655void SaturationSolvers::newton_raphson_twophase::build_arrays() {
1657 HelmholtzEOSMixtureBackend &rSatL = *(HEOS->SatL.get()), &rSatV = *(HEOS->SatV.get());
1662 rSatL.set_mole_fractions(x);
1663 rSatV.set_mole_fractions(y);
1668 rSatL.update_TP_guessrho(T, p, rhomolar_liq);
1669 rhomolar_liq = rSatL.rhomolar();
1670 rSatV.update_TP_guessrho(T, p, rhomolar_vap);
1671 rhomolar_vap = rSatV.rhomolar();
1676 p = 0.5 * (p_liq + p_vap);
1685 for (std::size_t i = 0; i < N; ++i) {
1689 r[i] = ln_f_liq - ln_f_vap;
1693 r[i + N] = (z[i] - x[i]) / (y[i] - x[i]) - beta;
1698 for (std::size_t i = 0; i < N; ++i) {
1699 for (std::size_t j = 0; j < N - 1; ++j) {
1705 if (imposed_variable == newton_raphson_twophase_options::P_IMPOSED) {
1708 }
else if (imposed_variable == newton_raphson_twophase_options::T_IMPOSED) {
1716 for (std::size_t i = 0; i < N - 1; ++i) {
1717 std::size_t k = i + N;
1718 J(k, i) = (z[i] - y[i]) / pow(y[i] - x[i], 2);
1719 J(k, i + (N - 1)) = -(z[i] - x[i]) / pow(y[i] - x[i], 2);
1722 error_rms = r.norm();
1728 const std::vector<double>&z, &lnK;
1744 lnK.resize(
z.size());
1746 double g0 = 0, g1 = 0,
beta = -1;
1748 for (
int i = 0; i < static_cast<int>(
z.size()); ++i) {
1750 if (
m_T < 0 &&
m_p < 0) {
1755 lnK[i] = SaturationSolvers::Wilson_lnK_factor(
HEOS,
m_T,
m_p, i);
1758 g0 +=
z[i] * (
K[i] - 1);
1759 g1 +=
z[i] * (1 - 1 /
K[i]);
1768 }
else if (g1 > 0) {
1788 HEOS.SatL->set_mole_fractions(x);
1789 HEOS.SatL->calc_reducing_state();
1790 HEOS.SatV->set_mole_fractions(y);
1791 HEOS.SatV->calc_reducing_state();
1794 std::cout <<
format(
"2) SS1: i beta K x y rho' rho''\n");
1796 for (
int step_count = 0; step_count < num_steps; ++step_count) {
1798 HEOS.SatL->set_mole_fractions(x);
1799 HEOS.SatV->set_mole_fractions(y);
1800 HEOS.SatL->calc_reducing_state();
1801 HEOS.SatV->calc_reducing_state();
1803 this->rho_TP_global();
1806 double g0 = 0, g1 = 0;
1807 for (std::size_t i = 0; i < z.size(); ++i) {
1808 lnK[i] = log(HEOS.SatL->fugacity_coefficient(i) / HEOS.SatV->fugacity_coefficient(i));
1810 g0 += z[i] * (K[i] - 1);
1811 g1 += z[i] * (1 - 1 / K[i]);
1816 }
else if (g1 > 0) {
1829 vec_to_string(y,
"%0.6f").c_str(), rhomolar_liq, rhomolar_vap);
1834 std::vector<double> tpdL, tpdH;
1837 double the_T = (m_T > 0 && m_p > 0) ? m_T : HEOS.T();
1838 double the_p = (m_T > 0 && m_p > 0) ? m_p : HEOS.p();
1844 HEOS.SatL->set_mole_fractions(z);
1845 HEOS.SatV->set_mole_fractions(z);
1846 HEOS.SatL->calc_reducing_state();
1847 HEOS.SatV->calc_reducing_state();
1850 double rhoL = HEOS.SatL->solver_rho_Tp_global(the_T, the_p, 0.9 / HEOS.SatL->SRK_covolume());
1851 double rhoV = HEOS.SatV->solver_rho_Tp_global(the_T, the_p, 0.9 / HEOS.SatV->SRK_covolume());
1852 HEOS.SatL->update_DmolarT_direct(rhoL, the_T);
1853 HEOS.SatV->update_DmolarT_direct(rhoV, the_T);
1857 this->tpd_liq = HEOS.SatL->tangent_plane_distance(the_T, the_p, x, rhomolar_liq);
1858 this->tpd_vap = HEOS.SatV->tangent_plane_distance(the_T, the_p, y, rhomolar_vap);
1860 this->DELTAG_nRT = (1 - beta) * tpd_liq + beta * (tpd_vap);
1862 std::cout <<
format(
"3) tpd': %g tpd'': %g DELTAG/nRT: %g\n", tpd_liq, tpd_vap, DELTAG_nRT);
1866 if (this->tpd_liq < -DBL_EPSILON || this->tpd_vap < -DBL_EPSILON || this->DELTAG_nRT < -
DBL_EPSILON) {
1868 std::cout <<
format(
"3) PHASE SPLIT beta in (eps,1-eps) \n");
1878 CoolPropDbl rho_bulk = HEOS.solver_rho_Tp_global(the_T, the_p, 0.9 / HEOS.SRK_covolume());
1879 HEOS.update_DmolarT_direct(rho_bulk, the_T);
1882 std::vector<double> fugacity_coefficient0(z.size()), fugacity0(z.size());
1883 for (std::size_t i = 0; i < z.size(); ++i) {
1884 fugacity_coefficient0[i] = HEOS.fugacity_coefficient(i);
1885 fugacity0[i] = HEOS.fugacity(i);
1889 xL.resize(z.size());
1890 xH.resize(z.size());
1891 for (std::size_t i = 0; i < z.size(); ++i) {
1892 xL[i] = z[i] * K0[i];
1893 xH[i] = z[i] / K0[i];
1900 std::cout <<
format(
"3) SS2: i x' x'' rho' rho'' tpd' tpd''\n");
1906 double diffbulkL = 0, diffbulkH = 0;
1907 for (
int step_count = 0; step_count < 100; ++step_count) {
1910 HEOS.SatL->set_mole_fractions(xH);
1911 HEOS.SatV->set_mole_fractions(xL);
1912 HEOS.SatL->calc_reducing_state();
1913 HEOS.SatV->calc_reducing_state();
1918 double tpd_L = 0, tpd_H = 0;
1919 for (std::size_t i = 0; i < xL.size(); ++i) {
1923 tpdL.push_back(tpd_L);
1924 tpdH.push_back(tpd_H);
1927 diffbulkL = 0, diffbulkH = 0;
1928 for (std::size_t i = 0; i < z.size(); ++i) {
1929 xL[i] = z[i] * fugacity_coefficient0[i] / HEOS.SatV->fugacity_coefficient(i);
1930 diffbulkL += std::abs(xL[i] - z[i]);
1931 xH[i] = z[i] * fugacity_coefficient0[i] / HEOS.SatL->fugacity_coefficient(i);
1932 diffbulkH += std::abs(xH[i] - z[i]);
1938 rhomolar_liq, rhomolar_vap, tpd_L, tpd_H);
1942 if (diffbulkL < 1e-2 || diffbulkH < 1e-2) {
1948 if (tpd_L < -1e-12 || tpd_H < -1e-12) {
1953 if (diffbulkH > 0.25 || diffbulkL > 0.25) {
1962 double the_T = (m_T > 0 && m_p > 0) ? m_T : HEOS.T();
1963 double the_p = (m_T > 0 && m_p > 0) ? m_p : HEOS.p();
1966 double rhoL = HEOS.SatL->solver_rho_Tp_global(the_T, the_p, 0.9 / HEOS.SatL->SRK_covolume());
1967 double rhoV = HEOS.SatV->solver_rho_Tp_global(the_T, the_p, 0.9 / HEOS.SatV->SRK_covolume());
1968 HEOS.SatL->update_DmolarT_direct(rhoL, the_T);
1969 HEOS.SatV->update_DmolarT_direct(rhoV, the_T);
1971 rhomolar_liq = HEOS.SatL->rhomolar();
1972 rhomolar_vap = HEOS.SatV->rhomolar();
1978 if (m_T > 0 && m_p > 0) {
1979 HEOS.SatL->update_TP_guessrho(m_T, m_p, rhomolar_liq);
1980 HEOS.SatV->update_TP_guessrho(m_T, m_p, rhomolar_vap);
1982 HEOS.SatL->update_TP_guessrho(HEOS.T(), HEOS.p(), rhomolar_liq);
1983 HEOS.SatV->update_TP_guessrho(HEOS.T(), HEOS.p(), rhomolar_vap);
1985 rhomolar_liq = HEOS.SatL->rhomolar();
1986 rhomolar_vap = HEOS.SatV->rhomolar();
1992 if (m_T > 0 && m_p > 0) {
1993 rhomolar_liq = HEOS.SatL->solver_rho_Tp_SRK(m_T, m_p,
iphase_liquid);
1994 rhomolar_vap = HEOS.SatV->solver_rho_Tp_SRK(m_T, m_p,
iphase_gas);
1996 rhomolar_liq = HEOS.SatL->solver_rho_Tp_SRK(HEOS.T(), HEOS.p(),
iphase_liquid);
1997 rhomolar_vap = HEOS.SatV->solver_rho_Tp_SRK(HEOS.T(), HEOS.p(),
iphase_gas);
2001 if (HEOS.backend_name().find(
"Helmholtz") == 0) {
2004 double summer_c = 0, v_SRK = 1 / rhomolar_liq;
2005 for (std::size_t i = 0; i < z.size(); ++i) {
2010 summer_c += z[i] * (0.40768 * R * Tc / pc * (0.29441 - pc / (rhomolarc * R * Tc)));
2012 rhomolar_liq = 1 / (v_SRK - summer_c);
2016void SaturationSolvers::PTflash_twophase::solve() {
2017 const std::size_t N = IO.x.size();
2019 double min_rel_change;
2031 Eigen::VectorXd v = J.colPivHouseholderQr().solve(-r);
2033 for (
unsigned int i = 0; i < N - 1; ++i) {
2034 err_rel[i] = v[i] / IO.x[i];
2036 err_rel[i + (N - 1)] = v[i + (N - 1)] / IO.y[i];
2037 IO.y[i] += v[i + (N - 1)];
2039 IO.x[N - 1] = 1 - std::accumulate(IO.x.begin(), IO.x.end() - 1, 0.0);
2040 IO.y[N - 1] = 1 - std::accumulate(IO.y.begin(), IO.y.end() - 1, 0.0);
2044 min_rel_change = err_rel.cwiseAbs().minCoeff();
2047 if (iter == IO.Nstep_max) {
2048 throw ValueError(
format(
"PTflash_twophase::call reached max number of iterations [%d]", IO.Nstep_max));
2050 }
while (this->error_rms > 1e-9 && min_rel_change > 1000 *
DBL_EPSILON && iter < IO.Nstep_max);
2052void SaturationSolvers::PTflash_twophase::build_arrays() {
2053 const std::size_t N = IO.x.size();
2055 r.resize(2 * N - 2);
2056 J.resize(2 * N - 2, 2 * N - 2);
2057 err_rel.resize(2 * N - 2);
2059 HEOS.SatL->set_mole_fractions(IO.x);
2060 HEOS.SatL->update_TP_guessrho(IO.T, IO.p, IO.rhomolar_liq);
2062 HEOS.SatV->set_mole_fractions(IO.y);
2063 HEOS.SatV->update_TP_guessrho(IO.T, IO.p, IO.rhomolar_vap);
2069 for (std::size_t k = 0; k < N; ++k) {
2070 r(k) = log(HEOS.SatL->fugacity(k) / HEOS.SatV->fugacity(k));
2071 for (std::size_t j = 0; j < N - 1; ++j) {
2082 for (std::size_t i = 0; i < N - 2; ++i) {
2083 std::size_t k = i + N;
2084 r(k) = (IO.z[i] - IO.x[i]) / (IO.y[i] - IO.x[i]) - (IO.z[N - 1] - IO.x[N - 1]) / (IO.y[N - 1] - IO.x[N - 1]);
2085 for (std::size_t j = 0; j < N - 2; ++j) {
2086 J(k, j) = (IO.z[j] - IO.x[j]) /
POW2(IO.y[j] - IO.x[j]);
2087 J(k, j + N - 1) = -(IO.z[j] - IO.x[j]) /
POW2(IO.y[j] - IO.x[j]);
2089 std::size_t j = N - 2;
2090 J(k, j) = -(IO.z[j] - IO.x[j]) /
POW2(IO.y[j] - IO.x[j]);
2091 J(k, j + N - 1) = +(IO.z[j] - IO.x[j]) /
POW2(IO.y[j] - IO.x[j]);
2093 this->error_rms = r.norm();
2097#if defined(ENABLE_CATCH)
2098# include <catch2/catch_all.hpp>
2100TEST_CASE(
"Check the PT flash calculation for two-phase inputs",
"[PTflash_twophase]") {
2102 AS->set_mole_fractions(std::vector<double>(2, 0.5));
2107 CoolProp::SaturationSolvers::PTflash_twophase_options o;
2108 o.x = AS->mole_fractions_liquid();
2109 o.y = AS->mole_fractions_vapor();
2110 o.z = AS->get_mole_fractions();
2117 solver.build_arrays();
2118 double err = solver.r.norm();
2119 REQUIRE(std::abs(err) < 1e-10);
2122 std::vector<double> x0 = o.x;
2124 o.x[1] = 1 - o.x[0];
2127 double diffx0 = o.x[0] - x0[0];
2128 REQUIRE(std::abs(diffx0) < 1e-10);