int freesteam_region_pv(double p, double v){ double p13 = freesteam_region4_psat_T(REGION1_TMAX); if(p > p13){ double v13 = freesteam_region1_v_pT(p, REGION1_TMAX); if(v < v13) return 1; /* region 2-3 */ double T23 = freesteam_b23_T_p(p); double v23 = freesteam_region2_v_pT(p,T23); if(v > v23) return 2; /* region 3? or high-pressure part of region 4? */ if(p >= IAPWS97_PCRIT) return 3; double Tsat = freesteam_region4_Tsat_p(p); double vf = 1./ freesteam_region4_rhof_T(Tsat); if(v < vf) return 3; double vg = 1./ freesteam_region4_rhog_T(Tsat); if(v > vg) return 3; return 4; }else{ double Tsat = freesteam_region4_Tsat_p(p); double vf = freesteam_region1_v_pT(p,Tsat); if(v < vf) return 1; double vg = freesteam_region2_v_pT(p,Tsat); if(v > vg) return 2; return 4; } }
int freesteam_bounds_pv(double p, double v, int verbose){ #define BOUND_WARN(MSG) \ if(verbose){\ fprintf(stderr,"%s (%s:%d): WARNING " MSG " (p = %g MPa, v = %g m3/kg)\n"\ ,__func__,__FILE__,__LINE__,p/1e6,v);\ } if(p <= 0){ BOUND_WARN("p <= 0"); return 1; } if(p > IAPWS97_PMAX){ BOUND_WARN("p > PMAX"); return 2; } double vmin = freesteam_region1_v_pT(p,IAPWS97_TMIN); if(v < vmin){ BOUND_WARN("v < v_region1(p,T_min)"); return 3; } double vmax = freesteam_region2_v_pT(p,REGION2_TMAX); if(v>vmax){ BOUND_WARN("v > v_region2(p,T_max)"); return 4; } return 0; #undef BOUND_WARN }
/** This function will never return region 4, because it's not possible to 'sit on the knife' of saturation. If you need to set saturated states, you should use another function such as freesteam_region1_set_Tx. */ SteamState freesteam_set_pT(double p, double T){ SteamState S; if(T < REGION1_TMAX){ if(p > freesteam_region4_psat_T(T)){ S.region = 1; S.R1.T = T; S.R1.p = p; }else{ S.region = 2; S.R2.T = T; S.R2.p = p; } }else{ //fprintf(stderr,"%s: T = %g >= REGION1_TMAX = %g\n",__func__,T,REGION1_TMAX); /* FIXME some optimisation possiblxe here with test for lower pressures */ double T23 = freesteam_b23_T_p(p); double p23min = freesteam_b23_p_T(REGION1_TMAX); if(p < p23min || T > T23){ //fprintf(stderr,"%s: T = %g > T23 = %g\n",__func__,T,T23); S.region = 2; S.R2.T = T; S.R2.p = p; }else{ /* FIXME the limit values are all wrong here! */ //fprintf(stderr,"%s: region 3\n",__func__); SteamPTData D = {p,T}; double ub = 1./freesteam_region1_v_pT(IAPWS97_PMAX,REGION1_TMAX); double lb = 1./freesteam_region2_v_pT(freesteam_b23_p_T(T),T); /* if we're in the little wee area around the critical pt... */ if(T < IAPWS97_TCRIT){ double psat = freesteam_region4_psat_T(T); if(p < psat){ ub = freesteam_region4_rhog_T(T); assert(lb<ub); }else{ lb = freesteam_region4_rhof_T(T); //fprintf(stderr,"lb = %g, ub = %g\n",lb,ub); assert(lb<ub); } } double tol = 1e-7; double sol, err = 0; if(zeroin_solve(&pT_region3_fn, &D, lb, ub, tol, &sol, &err)){ fprintf(stderr,"%s (%s:%d): failed to solve for rho\n",__func__,__FILE__,__LINE__); exit(1); } S.region = 3; S.R3.T = T; S.R3.rho = sol; //assert(fabs((freesteam_p(S) - p)/p) < tol); } } //fprintf(stderr,"%s: region %d\n",__func__,S.region); return S; }
double freesteam_region4_v_Tx(double T, double x){ double vf, vg; if(T < REGION1_TMAX){ double psat = freesteam_region4_psat_T(T); vf = freesteam_region1_v_pT(psat,T); vg = freesteam_region2_v_pT(psat,T); }else{ vf = 1./ freesteam_region4_rhof_T(T); vg = 1./ freesteam_region4_rhog_T(T); } return vf + x*(vg - vf); }
/** This function will always return saturated mixtures; no negative or >1 values of x are being 'understood' here (although one can give them meaning based on extrapolated values of u or h of v, for example...) */ SteamState freesteam_set_Tx(double T, double x) { SteamState S; if(T >= IAPWS97_TCRIT) { /* region 3 supercritical. just return a state with the specified temperature and the critical point entropy. arbitrary. */ SolveTSData D = {T, freesteam_region3_s_rhoT(IAPWS97_RHOCRIT, IAPWS97_TCRIT)}; double ub = 1./freesteam_region1_v_pT(IAPWS97_PMAX,REGION1_TMAX); double lb = 1./freesteam_region2_v_pT(freesteam_b23_p_T(T),T); double tol = 1e-7; double sol, err = 0; if(zeroin_solve(&Ts_region3_fn, &D, lb, ub, tol, &sol, &err)) { fprintf(stderr,"%s (%s:%d): failed to solve for rho\n",__func__,__FILE__,__LINE__); exit(1); } S.region = 3; S.R3.T = T; S.R3.rho = sol; } else if(x <= 0) { if(T > REGION1_TMAX) { S.region = 3; S.R3.T = T; S.R3.rho = freesteam_region4_rhof_T(T); /* FIXME iteratively refine the value */ } else { S.region = 1; S.R1.p = freesteam_region4_psat_T(T); S.R1.T = T; } } else if(x >= 1) { if(T > REGION1_TMAX) { S.region = 3; S.R3.T = T; S.R3.rho = freesteam_region4_rhog_T(T); /* FIXME iteratively refine the value */ } else { S.region = 2; S.R1.p = freesteam_region4_psat_T(T); S.R1.T = T; } } else { /* finally! */ S.region = 4; S.R4.T = T; S.R4.x = x; } return S; }
SteamState freesteam_set_pv(double p, double v){ SteamState S; S.region = (char)freesteam_region_pv(p,v); #if 0 int status; #endif switch(S.region){ case 1: /* iterate T to get correct value of v */ S.R1.p = p; S.R1.T = freesteam_region4_Tsat_p(p); { double lb = IAPWS97_TMIN; double ub = REGION1_TMAX; double tol = 1e-9; /* ??? */ double sol, err; SolvePVData D = {p, v}; zeroin_solve(&pv_region1_fn, &D, lb, ub, tol, &sol, &err); S.R1.T = sol; /* FIXME check convergence! */ } #if 0 S = freesteam_solver2_region1('p','v', p, v, S, &status); if(status){ fprintf(stderr,"%s: WARNING: Failed to converge in region 1\n",__func__); } #endif break; case 2: /* iterate T to get correct value of v */ S.R2.p = p; S.R2.T = freesteam_region4_Tsat_p(p); { double lb = IAPWS97_TMIN; double ub = IAPWS97_TMAX; double tol = 1e-9; /* ??? */ double sol, err; SolvePVData D = {p, v}; zeroin_solve(&pv_region2_fn, &D, lb, ub, tol, &sol, &err); S.R2.T = sol; /* FIXME check convergence! */ } #if 0 S.R2.p = p; S.R2.T = freesteam_region4_Tsat_p(p); S = freesteam_solver2_region2('p','v', p, v, S, &status); if(status){ fprintf(stderr,"%s: WARNING: Failed to converge in region 2\n",__func__); } #endif break; case 3: S.R3.rho = 1./ v; S.R3.T = REGION1_TMAX; { double lb = REGION1_TMAX; double ub = IAPWS97_TMAX; double tol = 1e-12; /* ??? */ double sol, err; SolvePRhoData D = {p, S.R3.rho}; zeroin_solve(&pv_region3_fn, &D, lb, ub, tol, &sol, &err); S.R3.T = sol; //fprintf(stderr,"%s: (p = %f MPa,v = %f m3/kg) region 3, error in p = %f\n",__func__,p,v, err); /* FIXME check convergence! */ } #if 0 S = freesteam_solver2_region3('p','v', p, v, S, &status); if(status){ fprintf(stderr,"%s: WARNING: Failed to converge in region 3\n",__func__); } #endif break; case 4: S.R4.T = freesteam_region4_Tsat_p(p); //fprintf(stderr,"%s: region 4, Tsat = %g\n",__func__,S.R4.T); double vf, vg; if(S.R4.T <= REGION1_TMAX){ vf = freesteam_region1_v_pT(p,S.R4.T); vg = freesteam_region2_v_pT(p,S.R4.T); }else{ /* TODO iteratively improve estimate of T */ vf = 1./ freesteam_region4_rhof_T(S.R4.T); vg = 1./ freesteam_region4_rhog_T(S.R4.T); } S.R4.x = (v - vf)/(vg - vf); } return S; }
double pv_region2_fn(double T, void *user_data){ return D->v - freesteam_region2_v_pT(D->p, T); }
//CL: drhodh=(drho/dh)_p=const Foam::scalar Foam::drhodh(SteamState S) { label region; scalar cp,beta,drhodh,rho; region=freesteam_region(S); if (region==1) { rho=1/freesteam_region1_v_pT(S.R1.p,S.R1.T); //Cl: note: in FreeStream, beta=1/V*(dV/dP)_P=const is called alphaV (in this region) beta=freesteam_region1_alphav_pT(S.R1.p,S.R1.T); cp=freesteam_region1_cp_pT(S.R1.p,S.R1.T); //CL: getting derivatives using Bridgmans table //CL: drhodh=(drho/dh)_p=const drhodh=-rho*beta/cp; } else if (region==2) { rho=1/freesteam_region2_v_pT(S.R2.p,S.R2.T); //Cl: note: in FreeStream, beta=1/V*(dV/dP)_P=const is called alphaV (in this region) //Cl: note: in FreeStream, kappa=1/V*(dV/dP)_T=const is called kappaT (in this region) beta=freesteam_region2_alphav_pT(S.R2.p,S.R2.T); cp=freesteam_region2_cp_pT(S.R2.p,S.R2.T); //CL: getting derivatives using Bridgmans table //CL: drhodh=(drho/dh)_p=const drhodh=-rho*beta/cp; } else if (region==3) { scalar gamma,cv,p; p=freesteam_region3_p_rhoT(S.R3.rho,S.R3.T); //Cl: note: beta=1/V*(dV/dP)_P=const //Cl: note: in FreeStream, gamma=1/p*(dp/dT)_v=const is called alphap (in this region gamma=freesteam_region3_alphap_rhoT(S.R3.rho,S.R3.T); cp=freesteam_region3_cp_rhoT(S.R3.rho,S.R3.T); cv=freesteam_region3_cv_rhoT(S.R3.rho,S.R3.T); beta=(cp-cv)/(S.R3.T/S.R3.rho*p*gamma); //CL: getting derivatives using Bridgmans table //CL: drhodh=(drho/dh)_p=const drhodh=-S.R3.rho*beta/cp; } else if (region==4) { scalar vv,vl,hl,hv,p; SteamState Sl,Sv; rho=1/freesteam_region4_v_Tx(S.R4.T,S.R4.x); p=freesteam_region4_psat_T(S.R4.T); //CL: Getting density on the vapour and liquid lines vv=1/freesteam_region4_rhog_T(S.R4.T); vl=1/freesteam_region4_rhof_T(S.R4.T); // getting the states outside the vapour dome Sl=freesteam_set_pv(p,vl-0.0000001); //inside region 1 Sv=freesteam_set_pv(p,vv+0.0000001); //inside region 2 hl=freesteam_region1_h_pT(Sl.R1.p,Sl.R1.T); hv=freesteam_region2_h_pT(Sv.R2.p,Sv.R2.T); //CL: drhodh=(drho/dh)_p=const drhodh=-rho*rho*(vv-vl)/(hv-hl); } else { Info<<"IAPWS-IF97.C error, outside the regions 1-4"<<endl; } return drhodh; }
//CL: psiH=(drho/dp)_h=const Foam::scalar Foam::psiH(SteamState S) { label region; scalar kappa,cp,beta,psiH,rho; region=freesteam_region(S); if (region==1) { //Cl: note: in FreeStream, beta=1/V*(dV/dP)_P=const is called alphaV (in this region) //Cl: note: in FreeStream, kappa=1/V*(dV/dP)_T=const is called kappaT (in this region) kappa=freesteam_region1_kappaT_pT(S.R1.p,S.R1.T); beta=freesteam_region1_alphav_pT(S.R1.p,S.R1.T); cp=freesteam_region1_cp_pT(S.R1.p,S.R1.T); rho=1/freesteam_region1_v_pT(S.R1.p,S.R1.T); //CL: getting derivatives using Bridgmans table //CL: psiH=(drho/dp)_h=const psiH=-((S.R1.T*beta*beta-beta)/cp-kappa*rho); } else if (region==2) { //Cl: note: in FreeStream, beta=1/V*(dV/dP)_P=const is called alphaV (in this region) //Cl: note: in FreeStream, kappa=1/V*(dV/dP)_T=const is called kappaT (in this region) kappa=freesteam_region2_kappaT_pT(S.R2.p,S.R2.T); beta=freesteam_region2_alphav_pT(S.R2.p,S.R2.T); cp=freesteam_region2_cp_pT(S.R2.p,S.R2.T); rho=1/freesteam_region2_v_pT(S.R2.p,S.R2.T); //CL: getting derivatives using Bridgmans table //CL: psiH=(drho/dp)_h=const psiH=-((S.R2.T*beta*beta-beta)/cp-kappa*rho); } else if (region==3) { scalar gamma,cv,p; rho=S.R3.rho; p=freesteam_region3_p_rhoT(S.R3.rho,S.R3.T); //Cl: note: beta=1/V*(dV/dP)_P=const //Cl: note: kappa=1/V*(dV/dP)_T=const //Cl: note: in FreeStream, gamma=1/p*(dp/dT)_v=const is called alphap (in this region gamma=freesteam_region3_alphap_rhoT(S.R3.rho,S.R3.T); cp=freesteam_region3_cp_rhoT(S.R3.rho,S.R3.T); cv=freesteam_region3_cv_rhoT(S.R3.rho,S.R3.T); beta=(cp-cv)/(S.R3.T/S.R3.rho*p*gamma); kappa=(cp-cv)/(S.R3.T/S.R3.rho*p*p*gamma*gamma); //CL: getting derivatives using Bridgmans table //CL: psiH=(drho/dp)_h=const psiH=-((S.R3.T*beta*beta-beta)/cp-kappa*rho); } else if (region==4) { scalar rhov,rhol,betav,betal,kappav,kappal,vv,vl,cpl,cpv,hl,hv,h,p; scalar dvldp,dvvdp,dhldp,dhvdp; scalar dpdT,dvdp,dxdp; SteamState Sl,Sv; rho=1/freesteam_region4_v_Tx(S.R4.T,S.R4.x); h=freesteam_region4_h_Tx(S.R4.T,S.R4.x); p=freesteam_region4_psat_T(S.R4.T); //CL: Getting density on the vapour and liquid lines rhov=freesteam_region4_rhog_T(S.R4.T); rhol=freesteam_region4_rhof_T(S.R4.T); vv=1/rhov; vl=1/rhol; //CL: getting derivatives --> this is a bit tricky in the vapor dome dpdT=freesteam_region4_dpsatdT_T(S.R4.T); // getting the states outside the vapour dome Sl=freesteam_set_pv(p,vl-0.0000001); //inside region 1 Sv=freesteam_set_pv(p,vv+0.0000001); //inside region 2 kappal=freesteam_region1_kappaT_pT(Sl.R1.p,Sl.R1.T); kappav=freesteam_region2_kappaT_pT(Sv.R2.p,Sv.R2.T); betal=freesteam_region1_alphav_pT(Sl.R1.p,Sl.R1.T); betav=freesteam_region2_alphav_pT(Sv.R2.p,Sv.R2.T); cpl=freesteam_region1_cp_pT(Sl.R1.p,Sl.R1.T); cpv=freesteam_region2_cp_pT(Sv.R2.p,Sv.R2.T); hl=freesteam_region1_h_pT(Sl.R1.p,Sl.R1.T); hv=freesteam_region2_h_pT(Sv.R2.p,Sv.R2.T); //calculation derviatives on liquid and vapour line dvldp=betal*vl/dpdT-kappal*vl; dvvdp=betav*vv/dpdT-kappav*vv; dhldp=vl*(1-betal*Sl.R1.T)+cpl/dpdT; dhvdp=vv*(1-betav*Sv.R2.T)+cpl/dpdT; dxdp=-dhldp/(hv-hl) +(h-hl)/((hv-hl)*(hv-hl)) *(dhvdp-dhldp); //CL: psiH=(drho/dp)_h=const dvdp=dvldp+(dvvdp-dvldp)*S.R4.x+(vv-vl)*dxdp; psiH=-rho*rho*dvdp; } else { Info<<"IAPWS-IF97.C error, outside the regions 1-4"<<endl; } return psiH; }
//CL: calculated the properties --> this function is called by the functions above //CL: does not calulated the internal energy, if this is needed e.g. for sonicFoam //CL: the function has to be changed a little bit void Foam::calculateProperties_h ( SteamState S, scalar &p, scalar &h, scalar &T, scalar &rho, scalar &psi, scalar &drhodh, scalar &mu, scalar &alpha, scalar &x ) { label region; scalar kappa,lambda,cp,beta; region=freesteam_region(S); if (region==1) { p=S.R1.p; T=S.R1.T; rho=1/freesteam_region1_v_pT(S.R1.p,S.R1.T); h=freesteam_region1_h_pT(S.R1.p,S.R1.T); x=0; //Cl: note: in FreeStream, beta=1/V*(dV/dP)_P=const is called alphaV (in this region) //Cl: note: in FreeStream, kappa=1/V*(dV/dP)_T=const is called kappaT (in this region) kappa=freesteam_region1_kappaT_pT(S.R1.p,S.R1.T); beta=freesteam_region1_alphav_pT(S.R1.p,S.R1.T); cp=freesteam_region1_cp_pT(S.R1.p,S.R1.T); //CL: getting derivatives using Bridgmans table //CL: psi=(drho/dp)_h=const //CL: drhodh=(drho/dh)_p=const psi=-((T*beta*beta-beta)/cp-kappa*rho); drhodh=-rho*beta/cp; //CL: getting transport properties mu=freesteam_mu_rhoT(rho, T); lambda=freesteam_k_rhoT(rho,T); alpha=lambda/cp; //Cl: Important info -->alpha= thermal diffusivity time density } else if (region==2) { p=S.R2.p; T=S.R2.T; rho=1/freesteam_region2_v_pT(S.R2.p,S.R2.T); h=freesteam_region2_h_pT(S.R2.p,S.R2.T); x=1; //Cl: note: in FreeStream, beta=1/V*(dV/dP)_P=const is called alphaV (in this region) //Cl: note: in FreeStream, kappa=1/V*(dV/dP)_T=const is called kappaT (in this region) kappa=freesteam_region2_kappaT_pT(S.R2.p,S.R2.T); beta=freesteam_region2_alphav_pT(S.R2.p,S.R2.T); cp=freesteam_region2_cp_pT(S.R2.p,S.R2.T); //CL: getting derivatives using Bridgmans table //CL: psi=(drho/dp)_h=const //CL: drhodh=(drho/dh)_p=const psi=-((T*beta*beta-beta)/cp-kappa*rho); drhodh=-rho*beta/cp; //CL: getting transport properties mu=freesteam_mu_rhoT(rho, T); lambda=freesteam_k_rhoT(rho,T); alpha=lambda/cp; //Cl: Important info -->alpha= thermal diffusivity time density } else if (region==3) { scalar gamma,cv; rho=S.R3.rho; T=S.R3.T; p=freesteam_region3_p_rhoT(S.R3.rho,S.R3.T); h=freesteam_region3_h_rhoT(S.R3.rho,S.R3.T); //CL= when h<h @ critical point -->x=0 else x=1 if (h<2084256.263) { x=0; } else { x=1; } //Cl: note: beta=1/V*(dV/dP)_P=const //Cl: note: kappa=1/V*(dV/dP)_T=const //Cl: note: in FreeStream, gamma=1/p*(dp/dT)_v=const is called alphap (in this region) gamma=freesteam_region3_alphap_rhoT(S.R3.rho,S.R3.T); cp=freesteam_region3_cp_rhoT(S.R3.rho,S.R3.T); cv=freesteam_region3_cv_rhoT(S.R3.rho,S.R3.T); beta=(cp-cv)/(S.R3.T/S.R3.rho*p*gamma); kappa=(cp-cv)/(S.R3.T/S.R3.rho*p*p*gamma*gamma); //CL: getting derivatives using Bridgmans table //CL: psi=(drho/dp)_h=const //CL: drhodh=(drho/dh)_p=const psi=-((T*beta*beta-beta)/cp-kappa*rho); drhodh=-rho*beta/cp; //CL: getting transport properties mu=freesteam_mu_rhoT(rho, T); lambda=freesteam_k_rhoT(rho,T); alpha=lambda/cp; //Cl: Important info -->alpha= thermal diffusivity time density } else if (region==4) { scalar rhov,rhol,betav,betal,kappav,kappal,vv,vl,cpl,cpv,hl,hv,cp; scalar dvldp,dvvdp,dhldp,dhvdp; scalar dpdT,dvdh,dvdp,dxdp; SteamState Sl,Sv; x=S.R4.x; T=S.R4.T; rho=1/freesteam_region4_v_Tx(S.R4.T,S.R4.x); h=freesteam_region4_h_Tx(S.R4.T,S.R4.x); p=freesteam_region4_psat_T(S.R4.T); cp=freesteam_region4_cp_Tx(S.R4.T,S.R4.x); //CL: Getting density on the vapour and liquid lines rhov=freesteam_region4_rhog_T(S.R4.T); rhol=freesteam_region4_rhof_T(S.R4.T); vv=1/rhov; vl=1/rhol; //CL: getting derivatives --> this is a bit tricky inside the vapor dome dpdT=freesteam_region4_dpsatdT_T(S.R4.T); // getting the states outside the vapour dome Sl=freesteam_set_pv(p,vl-0.0000001); //inside region 1 Sv=freesteam_set_pv(p,vv+0.0000001); //inside region 2 kappal=freesteam_region1_kappaT_pT(Sl.R1.p,Sl.R1.T); kappav=freesteam_region2_kappaT_pT(Sv.R2.p,Sv.R2.T); betal=freesteam_region1_alphav_pT(Sl.R1.p,Sl.R1.T); betav=freesteam_region2_alphav_pT(Sv.R2.p,Sv.R2.T); cpl=freesteam_region1_cp_pT(Sl.R1.p,Sl.R1.T); cpv=freesteam_region2_cp_pT(Sv.R2.p,Sv.R2.T); hl=freesteam_region1_h_pT(Sl.R1.p,Sl.R1.T); hv=freesteam_region2_h_pT(Sv.R2.p,Sv.R2.T); //calculation derviatives on liquid and vapour line dvldp=betal*vl/dpdT-kappal*vl; dvvdp=betav*vv/dpdT-kappav*vv; dhldp=vl*(1-betal*Sl.R1.T)+cpl/dpdT; dhvdp=vv*(1-betav*Sv.R2.T)+cpl/dpdT; dxdp=-dhldp/(hv-hl) +(h-hl)/((hv-hl)*(hv-hl)) *(dhvdp-dhldp); //CL: psi=(drho/dp)_h=const dvdp=dvldp+(dvvdp-dvldp)*x+(vv-vl)*dxdp; psi=-rho*rho*dvdp; //CL: drhodh=(drho/dh)_p=const dvdh=(vv-vl)/(hv-hl); drhodh=-rho*rho*dvdh; //CL: getting transport properties mu=freesteam_mu_rhoT(rho, T); lambda=freesteam_k_rhoT(rho,T); alpha=lambda/cp; //Cl: Important info -->alpha= thermal diffusivity time density } else { std::cout<<"IAPWS-IF97 error, outside the regions 1-4"<<std::endl; } }