5 #include "cantera/tpx/Sub.h"
15 static string fp2str(
double x,
string fmt=
"%g")
18 sprintf(buf, fmt.c_str(), x);
30 string TPX_Error::ErrorMessage =
"";
31 string TPX_Error::ErrorProcedure =
"";
33 string errorMsg(
int flag)
37 return "no convergence";
39 return "general error";
41 return "invalid input";
43 return "temperature error";
45 return "pressure error";
47 return "(unknown error)";
53 Substance::Substance() :
62 m_entropy_offset(0.0),
72 double ppp = (TwoPhase() ? Ps() : Pp());
73 return (Err ?
Undef : ppp);
76 const double DeltaT = 0.000001;
80 double Substance::dPsdT()
82 double ps1, tsave, dpdt;
86 dpdt = (Ps() - ps1)/DeltaT;
88 return (Err ?
Undef : dpdt);
92 int Substance::TwoPhase()
98 return ((Rho < Rhf) && (Rho > Rhv) ? 1 : 0);
104 double Substance::x()
108 return (1.0/Rho < Vcrit() ? 0.0 : 1.0);
113 }
else if (Rho >= Rhf) {
118 xx = (1.0/Rho - vl)/(vv - vl);
120 return (Err ?
Undef : xx);
125 double Substance::Tsat(
double p)
127 double Tsave, p_here, dp, dt, dpdt, dta,
129 if (Err || (p <= 0.0) || (p > Pcrit())) {
130 throw TPX_Error(
"Substance::Tsat",
"illegal pressure value");
135 double tol = 1.e-6*p;
138 T = 0.5*(Tcrit() - Tmin());
141 T = 0.5*(Tcrit() - Tmin());
164 if (LoopCount > 100) {
169 }
while (fabs(dp) > tol);
172 return (Err ?
Undef : tsat);
178 static const double TolAbsH = 0.0001;
179 static const double TolAbsU = 0.0001;
180 static const double TolAbsS = 1.e-7;
181 static const double TolAbsP = 0.000;
182 static const double TolAbsV = 1.e-8;
183 static const double TolAbsT = 1.e-3;
184 static const double TolRel = 3.e-8;
186 void Substance::Set(
int XY,
double x0,
double y0)
207 if (Lever(Pgiven, y0, x0, EvalH)) {
210 set_xy(EvalH, EvalP, x0, y0, TolAbsH, TolAbsP, TolRel, TolRel);
214 if (Lever(Pgiven, y0, x0, EvalS)) {
217 set_xy(EvalS, EvalP, x0, y0, TolAbsS, TolAbsP, TolRel, TolRel);
221 if (Lever(Pgiven, x0, y0, EvalV)) {
224 set_xy(EvalP, EvalV, x0, y0, TolAbsP, TolAbsV, TolRel, TolRel);
238 set_xy(EvalT, EvalP, x0, y0, TolAbsT, TolAbsP, TolRel, TolRel);
242 set_xy(EvalU, EvalV, x0, y0, TolAbsU, TolAbsV, TolRel, TolRel);
246 if (Lever(Tgiven, y0, x0, EvalS)) {
249 set_xy(EvalS, EvalT, x0, y0, TolAbsS, TolAbsT, TolRel, TolRel);
253 set_xy(EvalS, EvalV, x0, y0, TolAbsS, TolAbsV, TolRel, TolRel);
257 if (Lever(Pgiven, y0, x0, EvalU)) {
260 set_xy(EvalU, EvalP, x0, y0, TolAbsU, TolAbsP, TolRel, TolRel);
264 set_xy(EvalV, EvalH, x0, y0, TolAbsV, TolAbsH, TolRel, TolRel);
268 set_xy(EvalT, EvalH, x0, y0, TolAbsT, TolAbsH, TolRel, TolRel);
272 set_xy(EvalS, EvalH, x0, y0, TolAbsS, TolAbsH, TolRel, TolRel);
277 if ((y0 >= 0.0) && (y0 <= 1.0) && (temp < Tcrit())) {
280 Rho = 1.0/((1.0 - y0)/Rhf + y0/Rhv);
282 set_Err(InvalidInput);
287 if ((y0 >= 0.0) && (y0 <= 1.0) && (x0 < Tcrit())) {
290 Rho = 1.0/((1.0 - y0)/Rhf + y0/Rhv);
292 set_Err(InvalidInput);
297 set_Err(InvalidInput);
310 void Substance::set_Rho(
double r0)
315 set_Err(InvalidInput);
319 void Substance::set_T(
double t0)
321 if ((t0 >= Tmin()) && (t0 <= Tmax())) {
324 throw TPX_Error(
"Substance::set_T",
325 "illegal temperature value "+
fp2str(t0));
330 void Substance::set_v(
double v0)
335 throw TPX_Error(
"Substance::set_v",
336 "negative specific volume: "+
fp2str(v0));
337 set_Err(InvalidInput);
341 double Substance::Ps()
343 if (T < Tmin() || T > Tcrit()) {
344 throw TPX_Error(
"Substance::Ps",
345 "illegal temperature value "+
fp2str(T));
355 void Substance::Set_meta(
double phase,
double pp)
357 if (phase == Liquid) {
360 Rho = pp*MolWt()/(8314.0*T);
365 void Substance::update_sat()
367 if ((T != Tslast) && (T < Tcrit())) {
368 double Rho_save = Rho;
369 double gf, gv, dg, dp, dlp, psold;
372 double lps = log(pp);
376 for (i = 0; i<20; i++) {
387 Rho = pp*MolWt()/(8314.0*T);
402 if (fabs(dg) < 0.001 && Rhf > Rhv) {
405 dp = dg/(1.0/Rhv - 1.0/Rhf);
409 dlp = dg/(pp*(1.0/Rhv - 1.0/Rhf));
417 pp = psold + 0.5*(Pcrit() - psold);
419 }
else if (pp < 0.0) {
425 throw TPX_Error(
"Substance::update_sat",
426 "wrong root found for sat. liquid or vapor at P = "+
fp2str(pp));
434 throw TPX_Error(
"substance::update_sat",
"no convergence");
444 double Substance::vprop(
int ijob)
462 int Substance::Lever(
int itp,
double sat,
double val,
int ifunc)
468 double Valf, Valg, Tsave, Rhosave, xx, vv, psat;
472 if (sat >= Tcrit()) {
477 }
else if (itp == Pgiven) {
478 if (sat >= Pcrit()) {
490 throw TPX_Error(
"Substance::Lever",
"general error");
500 }
else if ((val >= Valf) && (val <= Valg)) {
501 xx = (val - Valf)/(Valg - Valf);
502 vv = (1.0 - xx)/Rhf + xx/Rhv;
513 void Substance::set_xy(
int ifx,
int ify,
double X,
double Y,
514 double atx,
double aty,
515 double rtx,
double rty)
518 double v_here, t_here, dv, dt, dxdt, dydt, dxdv, dydv,
519 det, x_here, y_here, dvm, dtm, dva, dta;
520 double Xa, Ya, err_x, err_y;
521 double dvs1 = 2.0*Vcrit();
522 double dvs2 = 0.7*Vcrit();
525 double v_save = 1.0/Rho;
533 Set(TV,Tcrit()*1.1,Vcrit()*1.1);
536 }
else if (Rho ==
Undef) {
537 Set(TV,T,Vcrit()*1.1);
556 err_x = fabs(X - x_here);
557 err_y = fabs(Y - y_here);
559 if ((err_x < atx + rtx*Xa) && (err_y < aty + rty*Ya)) {
565 if (t_here + dt > Tmax()) {
571 if (v_here <= Vcrit()) {
576 Set(TV, t_here + dt, v_here);
577 dxdt = (prop(ifx) - x_here)/dt;
578 dydt = (prop(ify) - y_here)/dt;
581 Set(TV, t_here, v_here + dv);
582 dxdv = (prop(ifx) - x_here)/dv;
583 dydv = (prop(ify) - y_here)/dv;
585 det = dxdt*dydv - dydt*dxdv;
586 dt = ((X - x_here)*dydv - (Y - y_here)*dxdv)/det;
587 dv = ((Y - y_here)*dxdt - (X - x_here)*dydt)/det;
607 if (t_here >= Tmax()) {
608 t_here = Tmax() - 0.001;
609 }
else if (t_here <= Tmin()) {
610 t_here = Tmin() + 0.001;
615 Set(TV, t_here, v_here);
617 if (LoopCount > 200) {
618 throw TPX_Error(
"Substance::set_xy",
"no convergence");
626 double Substance::prop(
int ijob)
628 double xx, pp, lp, vp, Rho_save;
636 if ((xx > 0.0) && (xx < 1.0)) {
642 pp = (1.0 - xx)*lp + xx*vp;
650 static const double ErrP = 1.e-7;
651 static const double Big = 1.e30;
653 void Substance::BracketSlope(
double Pressure)
656 dv = (v_here < Vcrit() ? -0.05*v_here : 0.2*v_here);
664 double dpdv = (Pmax - Pmin)/(Vmax - Vmin);
667 dv = dvbf*(Pressure - P_here)/dpdv;
672 void Substance::set_TPp(
double Temp,
double Pressure)
680 double dvs1 = 2.0*Vcrit();
681 double dvs2 = 0.7*Vcrit();
684 double v_save = 1.0/Rho;
689 while (P_here = Pp(),
690 fabs(Pressure - P_here) >= ErrP*Pressure || LoopCount == 0) {
692 BracketSlope(Pressure);
695 if (v_here <= Vcrit()) {
698 Set(TV, Temp, v_here+dv);
699 double dpdv = (Pp() - P_here)/dv;
701 BracketSlope(Pressure);
703 if ((P_here > Pressure) && (v_here > Vmin)) {
705 }
else if ((P_here < Pressure) && (v_here < Vmax)) {
708 if (v_here == Vmin) {
711 if (v_here == Vmax) {
715 throw TPX_Error(
"Substance::set_TPp",
"Vmin >= Vmax");
717 }
else if ((Vmin > 0.0) && (Vmax < Big)) {
723 BracketSlope(Pressure);
725 dv = (Pressure - P_here)/dpdv;
729 double dvm = 0.2*v_here;
737 double vt = v_here + dv;
738 if ((vt < Vmin) || (vt > Vmax)) {
739 dv = Vmin + (Pressure - Pmin)*(Vmax - Vmin)/(Pmax - Pmin) - v_here;
742 double dva = fabs(dv);
748 throw TPX_Error(
"Substance::set_TPp",
"dv = 0 and no convergence");
752 Set(TV, Temp, v_here);
754 if (LoopCount > 100) {
755 Set(TV, Temp, v_save);
756 throw TPX_Error(
"Substance::set_TPp",
string(
"no convergence for ")
757 +
"P* = "+
fp2str(Pressure/Pcrit())+
". V* = "
763 Set(TV, Temp,v_here);