Merge fully integrated real gas thermo. Author: Christian Lucas. Merge: Henrik Rusche

This commit is contained in:
Henrik Rusche 2016-06-07 13:46:53 +02:00
commit 235d99bd8e
171 changed files with 19913 additions and 18 deletions

63
README_RealGasBranch Normal file
View file

@ -0,0 +1,63 @@
Features
/*************************************Libraries**************************************************/
1. Included cubic equations of state for pure fluid.
--> Redlich Kwong --> class = redlichKwong
--> Peng Robinson --> class = pengRobinson
--> Soave Redlich Kwong --> class = soaveRedlichKwong
--> Aungier Redlich Kwong --> class = aungierRedlichKwong
2. Included cubic equations of state for mixtures.
TODO: connect the classes to the reaction models
-->class = mixtureRedlichKwong
-->class = mixturePengRobinson
-->class = mixtureSoaveRedlichKwong
-->class = aungierSoaveRedlichKwong
3. Included a new Thermo model
--> enthalpy calculated using NASA heat capacity polynomical
Added real gas correction in class
class = nasaHeatCapacityPolynomial
4. Minor changed in thermo related models so that they can be used with real gas classes
--> class = realGasSpecieThermo
--> class = sutherland
--> class = const
--> class = basicMixture
--> class = basicPsiThermo
5. Added enthalpy and internal energy thermodynamic class based on basicPsiThermo for real gases
--> enthalpy based thermo model, class = realGasHThermo
--> internal energy based thermo model, class = realGasEThermo
6. Added high precision water properties (IAPWS97) based on freeSteam (external program, not included)
Classes will not be compiled by Allwmake file
Classes will compile without freeSteam. Freesteam is loaded at runTime (see Tutorial)
--> classes = externalMedia/IAPWS_Waterproperties
/*************************************Solver**************************************************/
1. Changed pressure equation of rhoPisoFoam. Orginal pressure equation assumes perfect gas
(linear relationship between pressure and density)
--> new solver = realFluidPisoFoam
/*************************************Tutorials**************************************************/
1. pure fluid real gas mixture tutorial
--> realFluidPisoFoam/ras/backStep
2. IAPWS97 water properties tutorial
freeSteam must be installed for this tutorial
additional classes loaded in controlDict
--> realFluidPisoFoam/ras/cavity_IAPWS97
/*************************************Change log**************************************************/
git commit: "add branch ReadMe file"
--> added this file

View file

@ -0,0 +1,3 @@
realFluidPisoFoam.C
EXE = $(FOAM_APPBIN)/realFluidPisoFoam

View file

@ -0,0 +1,14 @@
EXE_INC = \
-I$(LIB_SRC)/thermophysicalModels/specie/lnInclude \
-I$(LIB_SRC)/thermophysicalModels/basic/lnInclude \
-I$(LIB_SRC)/turbulenceModels/compressible/turbulenceModel \
-I$(LIB_SRC)/finiteVolume/lnInclude
EXE_LIBS = \
-lfiniteVolume \
-lmeshTools \
-lbasicThermophysicalModels \
-lspecie \
-lcompressibleTurbulenceModel \
-lcompressibleRASModels \
-lcompressibleLESModels

View file

@ -0,0 +1,11 @@
fvVectorMatrix UEqn
(
fvm::ddt(rho, U)
+ fvm::div(phi, U)
+ turbulence->divDevRhoReff(U)
);
if (piso.momentumPredictor())
{
solve(UEqn == -fvc::grad(p));
}

View file

@ -0,0 +1,59 @@
Info<< "Reading thermophysical properties\n" << endl;
autoPtr<basicPsiThermo> pThermo
(
basicPsiThermo::New(mesh)
);
basicPsiThermo& thermo = pThermo();
volScalarField& p = thermo.p();
volScalarField& h = thermo.h();
const volScalarField& psi = thermo.psi();
const volScalarField& drhodh = thermo.drhodh();
volScalarField rho
(
IOobject
(
"rho",
runTime.timeName(),
mesh,
IOobject::NO_READ,
IOobject::AUTO_WRITE
),
thermo.rho()
);
Info<< "\nReading field U\n" << endl;
volVectorField U
(
IOobject
(
"U",
runTime.timeName(),
mesh,
IOobject::MUST_READ,
IOobject::AUTO_WRITE
),
mesh
);
# include "compressibleCreatePhi.H"
Info<< "Creating turbulence model\n" << endl;
autoPtr<compressible::turbulenceModel> turbulence
(
compressible::turbulenceModel::New
(
rho,
U,
phi,
thermo
)
);
Info<< "Creating field DpDt\n" << endl;
volScalarField DpDt =
fvc::DDt(surfaceScalarField("phiU", phi/fvc::interpolate(rho)), p);
mesh.schemesDict().setFluxRequired(p.name());

View file

@ -0,0 +1,12 @@
{
solve
(
fvm::ddt(rho, h)
+ fvm::div(phi, h)
- fvm::laplacian(turbulence->alphaEff(), h)
==
DpDt
);
thermo.correct();
}

View file

@ -0,0 +1,37 @@
rho = thermo.rho();
volScalarField rUA = 1.0/UEqn.A();
U = rUA*UEqn.H();
phi =
fvc::interpolate(rho)*
(
(fvc::interpolate(U) & mesh.Sf())
+ fvc::ddtPhiCorr(rUA, rho, U, phi)
);
while (piso.correctNonOrthogonal())
{
fvScalarMatrix pEqn
(
psi*fvm::ddt(p)
+ drhodh*fvc::ddt(h)
+ fvc::div(phi)
- fvm::laplacian(rho*rUA, p)
);
pEqn.solve();
if (piso.finalNonOrthogonalIter())
{
phi += pEqn.flux();
}
}
#include "rhoEqn.H"
#include "compressibleContinuityErrs.H"
U -= rUA*fvc::grad(p);
U.correctBoundaryConditions();
DpDt = fvc::DDt(surfaceScalarField("phiU", phi/fvc::interpolate(rho)), p);

View file

@ -0,0 +1,100 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright held by original author
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM; if not, write to the Free Software Foundation,
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Application
realFluidPisoFoam
Description
Transient PISO solver for compressible, laminar or turbulent flow
of real fluids e.g. real gases (cubic equations of state)
Solver cannot be used with perfect gas library
\*---------------------------------------------------------------------------*/
#include "fvCFD.H"
#include "basicPsiThermo.H"
#include "turbulenceModel.H"
#include "pisoControl.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
int main(int argc, char *argv[])
{
#include "setRootCase.H"
#include "createTime.H"
#include "createMesh.H"
pisoControl piso(mesh);
#include "createFields.H"
#include "initContinuityErrs.H"
#include "createTimeControls.H"
#include "compressibleCourantNo.H"
#include "setInitialDeltaT.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
Info<< "\nStarting time loop\n" << endl;
while (runTime.run())
{
#include "readTimeControls.H"
#include "compressibleCourantNo.H"
#include "setDeltaT.H"
runTime++;
Info<< "Time = " << runTime.timeName() << nl << endl;
#include "rhoEqn.H"
#include "UEqn.H"
// --- PISO loop
while (piso.correct())
{
#include "hEqn.H"
#include "pEqn.H"
}
turbulence->correct();
rho = thermo.rho();
runTime.write();
Info<< "ExecutionTime = " << runTime.elapsedCpuTime() << " s"
<< " ClockTime = " << runTime.elapsedClockTime() << " s"
<< nl << endl;
}
Info<< "End\n" << endl;
return 0;
}
// ************************************************************************* //

View file

@ -0,0 +1,599 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright held by original author
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM; if not, write to the Free Software Foundation,
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Author
Christian Lucas
Institut für Thermodynamik
Technische Universität Braunschweig
Germany
\*---------------------------------------------------------------------------*/
#include "IAPWS-IF97.H"
//CL: calculated all (minimal) needed properties for a given pressure and enthalpy
void Foam::calculateProperties_ph
(
scalar &p,
scalar &h,
scalar &T,
scalar &rho,
scalar &psi,
scalar &drhodh,
scalar &mu,
scalar &alpha
)
{
SteamState S;
// CL: vapor mass fraction is also calculated in calculateProperties_h
// CL: in this fuction, x is a dummy variable and x is not return to IAPWSThermo.C
scalar x;
S=freesteam_set_ph(p,h);
calculateProperties_h(S,p,h,T,rho,psi,drhodh,mu,alpha,x);
}
//CL: calculated all (minimal) needed properties + the vapor mass fraction for a given pressure and enthalpy
void Foam::calculateProperties_ph
(
scalar &p,
scalar &h,
scalar &T,
scalar &rho,
scalar &psi,
scalar &drhodh,
scalar &mu,
scalar &alpha,
scalar &x
)
{
SteamState S;
S=freesteam_set_ph(p,h);
calculateProperties_h(S,p,h,T,rho,psi,drhodh,mu,alpha,x);
}
//CL: calculated all (minimal) needed properties for a given pressure and temperature
void Foam::calculateProperties_pT
(
scalar &p,
scalar &T,
scalar &h,
scalar &rho,
scalar &psi,
scalar &drhodh,
scalar &mu,
scalar &alpha
)
{
SteamState S;
// CL: vapor mass fraction is also calculated in calculateProperties_h
// CL: in this fuction, x is a dummy variable and x is not return to IAPWSThermo.
scalar x;
S=freesteam_set_pT(p,T);
calculateProperties_h(S,p,h,T,rho,psi,drhodh,mu,alpha,x);
}
//CL: calculated all (minimal) needed properties + the vapor mass fraction for a given pressure and temperature
void Foam::calculateProperties_pT
(
scalar &p,
scalar &T,
scalar &h,
scalar &rho,
scalar &psi,
scalar &drhodh,
scalar &mu,
scalar &alpha,
scalar &x
)
{
SteamState S;
S=freesteam_set_pT(p,T);
calculateProperties_h(S,p,h,T,rho,psi,drhodh,mu,alpha,x);
}
//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,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;
}
}
//CL: returns density for given pressure and temperature
Foam::scalar Foam::rho_pT(scalar p,scalar T)
{
return 1/freesteam_v(freesteam_set_pT(p,T));
}
//CL: returns density for given pressure and enthalpy
Foam::scalar Foam::rho_ph(scalar p,scalar h)
{
return 1/freesteam_v(freesteam_set_ph(p,h));
}
//CL: returns Cp(heat capacity @ contant pressure) for given pressure and temperature
Foam::scalar Foam::cp_pT(scalar p,scalar T)
{
return freesteam_cp(freesteam_set_pT(p,T));
}
//CL: returns Cp(heat capacity @ contant pressure) for given pressure and enthalpy
Foam::scalar Foam::cp_ph(scalar p,scalar h)
{
return freesteam_cp(freesteam_set_ph(p,h));
}
//CL: returns Cv (heat capacity @ contant volume) for given pressure and temperature
Foam::scalar Foam::cv_pT(scalar p,scalar T)
{
return freesteam_cv(freesteam_set_pT(p,T));
}
//CL: returns Cv (heat capacity @ contant volume) for given pressure and enthalpy
Foam::scalar Foam::cv_ph(scalar p,scalar h)
{
return freesteam_cv(freesteam_set_ph(p,h));
}
//CL: returns enthalpy for given pressure and temperature
Foam::scalar Foam::h_pT(scalar p,scalar T)
{
return freesteam_h(freesteam_set_pT(p,T));
}
//CL: returns temperature for given pressure and enthalpy
Foam::scalar Foam::T_ph(scalar p,scalar h)
{
return freesteam_T(freesteam_set_ph(p,h));
}
//CL: psiH=(drho/dp)_h=const
Foam::scalar Foam::psiH_pT(scalar p,scalar T)
{
return psiH(freesteam_set_pT(p,T));
}
//CL: psiH=(drho/dp)_h=const
Foam::scalar Foam::psiH_ph(scalar p,scalar h)
{
return psiH(freesteam_set_ph(p,h));
}
//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,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;
//Keep compiler happy
psiH = 0;
}
return psiH;
}
//CL: drhodh=(drho/dh)_p=const
Foam::scalar Foam::drhodh_pT(scalar p,scalar T)
{
return drhodh(freesteam_set_pT(p,T));
}
//CL: drhodh=(drho/dh)_p=const
Foam::scalar Foam::drhodh_ph(scalar p,scalar h)
{
return drhodh(freesteam_set_ph(p,h));
}
//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;
// Keep compiler happy
drhodh = 0;
}
return drhodh;
}

View file

@ -0,0 +1,154 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright held by original author
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM; if not, write to the Free Software Foundation,
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Description
IAPWS-IF97 (water) based thermodynamic class. Water properties calculated by freeSteam.
This code connects OpenFoam with freeSteam and provides the basic functions needed in OpenFOAM
For more information about freeSteam and its authors have a look @ http://freesteam.sourceforge.net/example.php
SourceFiles
IAPWS-IF97.C
Author
Christian Lucas
Institut für Thermodynamik
Technische Universität Braunschweig
Germany
\*---------------------------------------------------------------------------*/
#ifndef IAPWSIF97_H
#define IAPWSIF97_H
#include "basicPsiThermo.H"
#include "steam.H"
namespace Foam
{
//CL: Functions to caluculate all fluid properties
void calculateProperties_h
(
SteamState S,
scalar &rho,
scalar &h,
scalar &T,
scalar &p,
scalar &psi,
scalar &drhodh,
scalar &mu,
scalar &alpha,
scalar &x
);
//CL: This functions returns all (minimal) needed propeties (p,T,h,rho,psi,drhodh,mu and alpha) for given p and T
void calculateProperties_pT
(
scalar &p,
scalar &T,
scalar &h,
scalar &rho,
scalar &psi,
scalar &drhodh,
scalar &mu,
scalar &alpha
);
//CL: This function returns the same values as the function above for given p and T
//CL: Additionally, the vapor mass fraction x is return
//CL: NOTE: This function is only included to have the possibility to update x at the fixedValue (Temperature) BC
//CL: can only return x=0 and x=1 because it is not possible to describe the vapour dome with p and T
void calculateProperties_pT
(
scalar &p,
scalar &T,
scalar &h,
scalar &rho,
scalar &psi,
scalar &drhodh,
scalar &mu,
scalar &alpha,
scalar &x
);
//CL: This functions returns all (minimal) needed properties (p,T,h,rho,psi,drhodh,mu and alpha) for given p and h
void calculateProperties_ph
(
scalar &p,
scalar &h,
scalar &T,
scalar &rho,
scalar &psi,
scalar &drhodh,
scalar &mu,
scalar &alpha
);
//CL: This function returns the same values as the function above for given p and h
//CL: Additionally, the vapor mass fraction x is return
void calculateProperties_ph
(
scalar &p,
scalar &h,
scalar &T,
scalar &rho,
scalar &psi,
scalar &drhodh,
scalar &mu,
scalar &alpha,
scalar &x
);
//CL: Return density for given pT or ph;
scalar rho_pT(scalar p,scalar T);
scalar rho_ph(scalar p,scalar h);
//CL: Return cp for given pT or ph;
scalar cp_pT(scalar p,scalar T);
scalar cp_ph(scalar p,scalar h);
//CL: Return cv for given pT or ph;
scalar cv_pT(scalar p,scalar T);
scalar cv_ph(scalar p,scalar h);
//CL: Return enthalpy for given pT;
scalar h_pT(scalar p,scalar T);
//CL: Return temperature for given ph;
scalar T_ph(scalar p,scalar T);
//CL: Return psiH=(drho/dp)_h=constant for given pT or ph;
scalar psiH_pT(scalar p,scalar T);
scalar psiH_ph(scalar p,scalar h);
scalar psiH(SteamState S);
//CL: Return drhodh=(drho/dh)_p=constant for given pT or ph;
scalar drhodh_pT(scalar p,scalar T);
scalar drhodh_ph(scalar p,scalar h);
scalar drhodh(SteamState S);
}
#endif //IAPWSIF97_C_

View file

@ -0,0 +1,477 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright held by original author
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM; if not, write to the Free Software Foundation,
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Author
Christian Lucas
Institut für Thermodynamik
Technische Universität Braunschweig
Germany
\*---------------------------------------------------------------------------*/
#include "IAPWSThermo.H"
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
void Foam::IAPWSThermo::calculate()
{
scalarField& hCells = h_.internalField();
scalarField& pCells = this->p_.internalField();
scalarField& TCells = this->T_.internalField();
scalarField& rhoCells= this->rho_.internalField();
scalarField& psiCells = this->psi_.internalField();
scalarField& drhodhCells = this->drhodh_.internalField();
scalarField& muCells = this->mu_.internalField();
scalarField& alphaCells = this->alpha_.internalField();
//CL: Updating all cell properties
//CL: loop through all cells
forAll(TCells, celli)
{
//CL: see IAPWAS-IF97.H
calculateProperties_ph
(
pCells[celli],
hCells[celli],
TCells[celli],
rhoCells[celli],
psiCells[celli],
drhodhCells[celli],
muCells[celli],
alphaCells[celli]
);
}
//CL: loop through all patches
forAll(T_.boundaryField(), patchi)
{
fvPatchScalarField& pp = this->p_.boundaryField()[patchi];
fvPatchScalarField& pT = this->T_.boundaryField()[patchi];
fvPatchScalarField& ppsi = this->psi_.boundaryField()[patchi];
fvPatchScalarField& pdrhodh = this->drhodh_.boundaryField()[patchi];
fvPatchScalarField& prho = this->rho_.boundaryField()[patchi];
fvPatchScalarField& ph = this->h_.boundaryField()[patchi];
fvPatchScalarField& pmu = this->mu_.boundaryField()[patchi];
fvPatchScalarField& palpha = this->alpha_.boundaryField()[patchi];
//CL: Updating the patch properties for patches with fixed temperature BC's
if (pT.fixesValue())
{
forAll(pT, facei)
{
//CL: see IAPWAS-IF97.H
calculateProperties_pT
(
pp[facei],
pT[facei],
ph[facei],
prho[facei],
ppsi[facei],
pdrhodh[facei],
pmu[facei],
palpha[facei]
);
}
}
//CL: Updating the patch properties for patches without fixed temperature BC's
else
{
forAll(pT, facei)
{
//CL: see IAPWAS-IF97.H
calculateProperties_ph
(
pp[facei],
ph[facei],
pT[facei],
prho[facei],
ppsi[facei],
pdrhodh[facei],
pmu[facei],
palpha[facei]
);
}
}
}
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::IAPWSThermo::IAPWSThermo
(
const fvMesh& mesh,
const objectRegistry& obj
)
:
basicPsiThermo(mesh, obj),
h_
(
IOobject
(
"h",
mesh.time().timeName(),
obj,
IOobject::NO_READ,
IOobject::NO_WRITE
),
mesh,
dimensionSet(0, 2, -2, 0, 0),
this->hBoundaryTypes()
),
rho_
(
IOobject
(
"rhoThermo",
mesh.time().timeName(),
obj,
IOobject::READ_IF_PRESENT,
IOobject::NO_WRITE
),
mesh,
dimDensity
),
drhodh_
(
IOobject
(
"drhodh",
mesh.time().timeName(),
obj,
IOobject::NO_READ,
IOobject::NO_WRITE
),
mesh,
dimensionSet(1, -5, 2, 0, 0)
)
{
scalarField& hCells = h_.internalField();
scalarField& TCells = this->T_.internalField();
scalarField& pCells =this->p_.internalField();
scalarField& rhoCells =this->rho_.internalField();
forAll(hCells, celli)
{
hCells[celli] = h_pT(pCells[celli],TCells[celli]);
}
forAll(h_.boundaryField(), patchi)
{
h_.boundaryField()[patchi] ==
h(this->T_.boundaryField()[patchi], patchi);
}
forAll(rhoCells, celli)
{
rhoCells[celli] = rho_pT(pCells[celli],TCells[celli]);
}
forAll(rho_.boundaryField(), patchi)
{
rho_.boundaryField()[patchi] ==
rho(this->p_.boundaryField()[patchi] ,this->h_.boundaryField()[patchi], patchi);
}
hBoundaryCorrection(h_);
calculate();
// Switch on saving old time
this->psi_.oldTime();
}
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
Foam::IAPWSThermo::~IAPWSThermo()
{}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
void Foam::IAPWSThermo::correct()
{
if (debug)
{
Info<< "entering IAPWSThermo::correct()" << endl;
}
// force the saving of the old-time values
this->psi_.oldTime();
calculate();
if (debug)
{
Info<< "exiting IAPWSThermo::correct()" << endl;
}
}
Foam::tmp<Foam::scalarField> Foam::IAPWSThermo::h
(
const scalarField& T,
const labelList& cells
) const
{
//getting pressure field
const scalarField& pCells = this->p_.internalField();
tmp<scalarField> th(new scalarField(T.size()));
scalarField& h = th();
forAll(T, celli)
{
h[celli] = h_pT(pCells[cells[celli]],T[celli]);
}
return th;
}
Foam::tmp<Foam::scalarField> Foam::IAPWSThermo::h
(
const scalarField& T,
const label patchi
) const
{
// getting pressure at the patch
const fvPatchScalarField& pp = this->p_.boundaryField()[patchi];
tmp<scalarField> th(new scalarField(T.size()));
scalarField& h = th();
forAll(T, facei)
{
h[facei] = h_pT(pp[facei], T[facei]);
}
return th;
}
//CL: Calculates rho at patch
Foam::tmp<Foam::scalarField> Foam::IAPWSThermo::rho
(
const scalarField& p,
const scalarField& h,
const label patchi
) const
{
tmp<scalarField> trho(new scalarField(h.size()));
scalarField& rho = trho();
forAll(h, facei)
{
rho[facei] = rho_ph(p[facei], h[facei]);
}
return trho;
}
Foam::tmp<Foam::scalarField> Foam::IAPWSThermo::Cp
(
const scalarField& T,
const label patchi
) const
{
// getting pressure at the patch
const fvPatchScalarField& pp = this->p_.boundaryField()[patchi];
tmp<scalarField> tCp(new scalarField(T.size()));
scalarField& cp = tCp();
forAll(T, facei)
{
cp[facei] = cp_ph(pp[facei],h_pT(pp[facei], T[facei]));
}
return tCp;
}
Foam::tmp<Foam::volScalarField> Foam::IAPWSThermo::Cp() const
{
const fvMesh& mesh = this->T_.mesh();
tmp<volScalarField> tCp
(
new volScalarField
(
IOobject
(
"Cp",
mesh.time().timeName(),
this->T_.db(),
IOobject::NO_READ,
IOobject::NO_WRITE
),
mesh,
dimensionSet(0, 2, -2, -1, 0)
)
);
volScalarField& cp = tCp();
forAll(this->T_, celli)
{
cp[celli] = cp_ph(this->p_[celli], this->h_[celli]);
}
forAll(this->T_.boundaryField(), patchi)
{
const fvPatchScalarField& pp = this->p_.boundaryField()[patchi];
const fvPatchScalarField& ph = this->h_.boundaryField()[patchi];
fvPatchScalarField& pCp = cp.boundaryField()[patchi];
forAll(ph, facei)
{
pCp[facei] = cp_ph(pp[facei], ph[facei]);
}
}
return tCp;
}
//CL: Returns an updated field for rho
Foam::tmp<Foam::volScalarField> Foam::IAPWSThermo::rho() const
{
const fvMesh& mesh = this->p_.mesh();
tmp<volScalarField> prho
(
new volScalarField
(
IOobject
(
"rhoThermo2",
mesh.time().timeName(),
this->T_.db(),
IOobject::NO_READ,
IOobject::NO_WRITE
),
mesh,
dimDensity
)
);
volScalarField& rho = prho();
forAll(this->p_, celli)
{
rho[celli] = rho_ph(this->p_[celli], this->h_[celli]);
}
forAll(this->T_.boundaryField(), patchi)
{
const fvPatchScalarField& pp = this->p_.boundaryField()[patchi];
const fvPatchScalarField& ph = this->h_.boundaryField()[patchi];
fvPatchScalarField& prho = rho.boundaryField()[patchi];
forAll(ph, facei)
{
prho[facei] = rho_ph(pp[facei], ph[facei]);
}
}
return prho;
}
Foam::tmp<Foam::scalarField> Foam::IAPWSThermo::Cv
(
const scalarField& T,
const label patchi
) const
{
// getting pressure at the patch
const fvPatchScalarField& pp = this->p_.boundaryField()[patchi];
tmp<scalarField> tCv(new scalarField(T.size()));
scalarField& cv = tCv();
forAll(T, facei)
{
cv[facei] = cv_ph(pp[facei], h_pT(pp[facei], T[facei]));
}
return tCv;
}
Foam::tmp<Foam::volScalarField> Foam::IAPWSThermo::Cv() const
{
const fvMesh& mesh = this->T_.mesh();
tmp<volScalarField> tCv
(
new volScalarField
(
IOobject
(
"Cv",
mesh.time().timeName(),
this->T_.db(),
IOobject::NO_READ,
IOobject::NO_WRITE
),
mesh,
dimensionSet(0, 2, -2, -1, 0)
)
);
volScalarField& cv = tCv();
forAll(this->h_, celli)
{
cv[celli] = cv_ph(this->p_[celli], this->h_[celli]);
}
forAll(this->T_.boundaryField(), patchi)
{
cv.boundaryField()[patchi] =
Cv(this->T_.boundaryField()[patchi], patchi);
}
return tCv;
}
bool Foam::IAPWSThermo::read()
{
basicPsiThermo::read();
return true;
}
// ************************************************************************* //

View file

@ -0,0 +1,201 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright held by original author
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM; if not, write to the Free Software Foundation,
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Class
Foam::IAPWSThermo
Description:
Waterproperties based on the IAPWS 97 tables
The water properties are caluclated using freeSteam (http://freesteam.sourceforge.net/example.php)
General paper decribing the water tables:
"Revised Release on the IAPWS Industrial Formulation 1997 for the Thermodynamic Properties of Water and Steam"
SourceFiles
IAPWSThermo.C
Author
Christian Lucas
Institut für Thermodynamik
Technische Universität Braunschweig
Germany
\*---------------------------------------------------------------------------*/
#ifndef IAPWSThermo_H
#define IAPWSThermo_H
#include "basicPsiThermo.H"
#include "IAPWS-IF97.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
/*---------------------------------------------------------------------------*\
Class IAPWSTHERMO Declaration
\*---------------------------------------------------------------------------*/
class IAPWSThermo
:
public basicPsiThermo
{
// Private data
//- Enthalpy field
volScalarField h_;
//- DensityField
volScalarField rho_;
// CL:drhodh Field
// CL:needed for pressure equation
volScalarField drhodh_;
// Private member functions
//- Calculate the thermo variables
void calculate();
//- Construct as copy (not implemented)
IAPWSThermo(const IAPWSThermo&);
public:
//- Runtime type information
TypeName("IAPWSThermo");
// Constructors
//- Construct from mesh
IAPWSThermo(const fvMesh&, const objectRegistry& obj);
//- Destructor
virtual ~IAPWSThermo();
// Member functions
//- Update properties
virtual void correct();
// Access to thermodynamic state variables
//- Enthalpy [J/kg]
// Non-const access allowed for transport equations
virtual volScalarField& h()
{
return h_;
}
//- Enthalpy [J/kg]
virtual const volScalarField& h() const
{
return h_;
}
// Fields derived from thermodynamic state variables
//- Enthalpy for cell-set [J/kg]
virtual tmp<scalarField> h
(
const scalarField& T,
const labelList& cells
) const;
//- Enthalpy for patch [J/kg]
virtual tmp<scalarField> h
(
const scalarField& T,
const label patchi
) const;
//- Density for patch [J/kg]
virtual tmp<scalarField> rho
(
const scalarField& p,
const scalarField& h,
const label patchi
) const;
//- Heat capacity at constant pressure for patch [J/kg/K]
// dummy function needed for BC
virtual tmp<scalarField> Cp
(
const scalarField& T,
const label patchi
) const;
//- Heat capacity at constant pressure [J/kg/K]
virtual tmp<volScalarField> Cp() const;
//- Heat capacity at constant volume for patch [J/kg/K]
virtual tmp<scalarField> Cv
(
const scalarField& T,
const label patchi
) const;
//- Heat capacity at constant volume [J/kg/K]
virtual tmp<volScalarField> Cv() const;
//- Gradient drhodh @ constant pressure
virtual const volScalarField& drhodh() const
{
return drhodh_;
}
//- Density [kg/m^3] - uses current value of pressure
virtual tmp<volScalarField> rho() const;
//- Read thermophysicalProperties dictionary
virtual bool read();
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#ifdef NoRepository
# include "IAPWSThermo.C"
#endif
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View file

@ -0,0 +1,53 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright held by original author
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM; if not, write to the Free Software Foundation,
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Author
Christian Lucas
Institut für Thermodynamik
Technische Universität Braunschweig
Germany
\*---------------------------------------------------------------------------*/
#include "makeBasicPsiThermo.H"
#include "IAPWSThermo.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
/* * * * * * * * * * * * * * * private static data * * * * * * * * * * * * * */
makeBasicExternalLibraryBasedThermo
(
IAPWSThermo
);
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// ************************************************************************* //

View file

@ -0,0 +1,135 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright held by original author
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM; if not, write to the Free Software Foundation,
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Description:
Includes the definition of a struct from freestream
Code copied from freestream --> steam.h
\*---------------------------------------------------------------------------*/
#ifdef __cplusplus
#define EXTERN extern "C"
#else
#define EXTERN extern
#endif
typedef struct SteamState_R1_struct{
double p, T;
} SteamState_R1;
typedef struct SteamState_R2_struct{
double p, T;
} SteamState_R2;
typedef struct SteamState_R3_struct{
double rho, T;
} SteamState_R3;
typedef struct SteamState_R4_struct{
double T, x;
} SteamState_R4;
typedef struct SteamState_struct{
char region;
union{
SteamState_R1 R1;
SteamState_R2 R2;
SteamState_R3 R3;
SteamState_R4 R4;
};
} SteamState;
//CL:
EXTERN double freesteam_p(SteamState S);
EXTERN double freesteam_T(SteamState S);
EXTERN double freesteam_rho(SteamState S);
EXTERN double freesteam_v(SteamState S);
EXTERN double freesteam_u(SteamState S);
EXTERN double freesteam_h(SteamState S);
EXTERN double freesteam_s(SteamState S);
EXTERN double freesteam_cp(SteamState S);
EXTERN double freesteam_cv(SteamState S);
EXTERN double freesteam_w(SteamState S);
EXTERN double freesteam_x(SteamState S);
EXTERN double freesteam_mu(SteamState S);
EXTERN double freesteam_k(SteamState S);
//CL: getting SteamState for two given properties e.g. pressure and temperatur
EXTERN SteamState freesteam_set_pv(double,double);
EXTERN SteamState freesteam_set_pu(double,double);
EXTERN SteamState freesteam_set_pT(double,double);
EXTERN SteamState freesteam_set_ph(double,double);
//CL: getting region of the SteamState
EXTERN int freesteam_region(SteamState);
//CL: transport properties
EXTERN double freesteam_mu_rhoT(double,double);
EXTERN double freesteam_k_rhoT(double,double);
//CL: Region 1 --> see region1.h (freesteam)
EXTERN double freesteam_region1_v_pT(double,double);
EXTERN double freesteam_region1_h_pT(double,double);
EXTERN double freesteam_region1_kappaT_pT(double,double);
EXTERN double freesteam_region1_alphav_pT(double,double);
EXTERN double freesteam_region1_cp_pT(double,double);
EXTERN double freesteam_region1_u_pT(double,double);
EXTERN double freesteam_region1_s_pT(double,double);
EXTERN double freesteam_region1_cv_pT(double,double);
//CL: Region 2 --> see region2.h (freesteam)
EXTERN double freesteam_region2_v_pT(double,double);
EXTERN double freesteam_region2_u_pT(double,double);
EXTERN double freesteam_region2_s_pT(double,double);
EXTERN double freesteam_region2_h_pT(double,double);
EXTERN double freesteam_region2_cp_pT(double,double);
EXTERN double freesteam_region2_cv_pT(double,double);
EXTERN double freesteam_region2_alphav_pT(double,double);
EXTERN double freesteam_region2_kappaT_pT(double,double);
//CL: Region 3 --> see region3.h (freesteam)
EXTERN double freesteam_region3_p_rhoT(double,double);
EXTERN double freesteam_region3_u_rhoT(double,double);
EXTERN double freesteam_region3_s_rhoT(double,double);
EXTERN double freesteam_region3_h_rhoT(double,double);
EXTERN double freesteam_region3_cp_rhoT(double,double);
EXTERN double freesteam_region3_cv_rhoT(double,double);
EXTERN double freesteam_region3_alphap_rhoT(double,double);
EXTERN double freesteam_region3_betap_rhoT(double,double);
//CL: Region 4 --> see region4.h (freesteam)
EXTERN double freesteam_region4_psat_T(double);
EXTERN double freesteam_region4_Tsat_p(double);
EXTERN double freesteam_region4_rhof_T(double);
EXTERN double freesteam_region4_rhog_T(double);
EXTERN double freesteam_region4_v_Tx(double,double);
EXTERN double freesteam_region4_u_Tx(double,double);
EXTERN double freesteam_region4_h_Tx(double,double);
EXTERN double freesteam_region4_s_Tx(double,double);
EXTERN double freesteam_region4_cp_Tx(double,double);
EXTERN double freesteam_region4_cv_Tx(double,double);
EXTERN double freesteam_region4_dpsatdT_T(double);

View file

@ -8,12 +8,17 @@ psiThermo/basicPsiThermo/newBasicPsiThermo.C
psiThermo/hPsiThermo/hPsiThermos.C
psiThermo/hsPsiThermo/hsPsiThermos.C
psiThermo/ePsiThermo/ePsiThermos.C
psiThermo/realGasHThermo/realGasHThermos.C
psiThermo/realGasEThermo/realGasEThermos.C
rhoThermo/basicRhoThermo/basicRhoThermo.C
rhoThermo/basicRhoThermo/newBasicRhoThermo.C
rhoThermo/hRhoThermo/hRhoThermos.C
rhoThermo/hsRhoThermo/hsRhoThermos.C
IAPWS_Waterproperties/IAPWSThermo/IAPWS-IF97.C
IAPWS_Waterproperties/IAPWSThermo/IAPWSThermos.C
derivedFvPatchFields/fixedEnthalpy/fixedEnthalpyFvPatchScalarField.C
derivedFvPatchFields/gradientEnthalpy/gradientEnthalpyFvPatchScalarField.C
derivedFvPatchFields/mixedEnthalpy/mixedEnthalpyFvPatchScalarField.C

View file

@ -1,7 +1,9 @@
EXE_INC = \
-I$(LIB_SRC)/finiteVolume/lnInclude \
-I$(LIB_SRC)/thermophysicalModels/specie/lnInclude
-I$(LIB_SRC)/thermophysicalModels/specie/lnInclude \
-I$(LIB_SRC)/thermophysicalModels/thermophysicalFunctions/lnInclude
LIB_LIBS = \
-lspecie \
-lthermophysicalFunctions \
-lfiniteVolume

View file

@ -1,25 +1,26 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | foam-extend: Open Source CFD
\\ / O peration | Version: 3.2
\\ / A nd | Web: http://www.foam-extend.org
\\/ M anipulation | For copyright notice see file Copyright
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright held by original author
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of foam-extend.
This file is part of OpenFOAM.
foam-extend is free software: you can redistribute it and/or modify it
OpenFOAM is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation, either version 3 of the License, or (at your
Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
foam-extend is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with foam-extend. If not, see <http://www.gnu.org/licenses/>.
along with OpenFOAM; if not, write to the Free Software Foundation,
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Description
Mixture instantiation
@ -32,12 +33,19 @@ Description
#include "makeBasicMixture.H"
#include "perfectGas.H"
#include "redlichKwong.H"
#include "pengRobinson.H"
#include "aungierRedlichKwong.H"
#include "soaveRedlichKwong.H"
#include "eConstThermo.H"
#include "hConstThermo.H"
#include "janafThermo.H"
#include "nasaHeatCapacityPolynomial.H"
#include "constantHeatCapacity.H"
#include "specieThermo.H"
#include "realGasSpecieThermo.H"
#include "constTransport.H"
#include "sutherlandTransport.H"
@ -101,6 +109,150 @@ makeBasicMixturePhys
icoPoly8ThermoPhysics
);
makeBasicRealFluidMixture
(
pureMixture,
sutherlandTransport,
realGasSpecieThermo,
nasaHeatCapacityPolynomial,
redlichKwong
);
makeBasicRealFluidMixture
(
pureMixture,
sutherlandTransport,
realGasSpecieThermo,
nasaHeatCapacityPolynomial,
pengRobinson
);
makeBasicRealFluidMixture
(
pureMixture,
sutherlandTransport,
realGasSpecieThermo,
nasaHeatCapacityPolynomial,
aungierRedlichKwong
);
makeBasicRealFluidMixture
(
pureMixture,
sutherlandTransport,
realGasSpecieThermo,
nasaHeatCapacityPolynomial,
soaveRedlichKwong
);
makeBasicRealFluidMixture
(
pureMixture,
constTransport,
realGasSpecieThermo,
nasaHeatCapacityPolynomial,
redlichKwong
);
makeBasicRealFluidMixture
(
pureMixture,
constTransport,
realGasSpecieThermo,
nasaHeatCapacityPolynomial,
pengRobinson
);
makeBasicRealFluidMixture
(
pureMixture,
constTransport,
realGasSpecieThermo,
nasaHeatCapacityPolynomial,
aungierRedlichKwong
);
makeBasicRealFluidMixture
(
pureMixture,
constTransport,
realGasSpecieThermo,
nasaHeatCapacityPolynomial,
soaveRedlichKwong
);
makeBasicRealFluidMixture
(
pureMixture,
sutherlandTransport,
realGasSpecieThermo,
constantHeatCapacity,
redlichKwong
);
makeBasicRealFluidMixture
(
pureMixture,
sutherlandTransport,
realGasSpecieThermo,
constantHeatCapacity,
pengRobinson
);
makeBasicRealFluidMixture
(
pureMixture,
sutherlandTransport,
realGasSpecieThermo,
constantHeatCapacity,
aungierRedlichKwong
);
makeBasicRealFluidMixture
(
pureMixture,
sutherlandTransport,
realGasSpecieThermo,
constantHeatCapacity,
soaveRedlichKwong
);
makeBasicRealFluidMixture
(
pureMixture,
constTransport,
realGasSpecieThermo,
constantHeatCapacity,
redlichKwong
);
makeBasicRealFluidMixture
(
pureMixture,
constTransport,
realGasSpecieThermo,
constantHeatCapacity,
pengRobinson
);
makeBasicRealFluidMixture
(
pureMixture,
constTransport,
realGasSpecieThermo,
constantHeatCapacity,
aungierRedlichKwong
);
makeBasicRealFluidMixture
(
pureMixture,
constTransport,
realGasSpecieThermo,
constantHeatCapacity,
soaveRedlichKwong
);
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

View file

@ -56,6 +56,26 @@ defineTemplateTypeNameAndDebugWithName \
0 \
);
#define makeBasicRealFluidMixture(Mixture,Transport,SpecieThermo,Thermo,EqnOfState) \
\
typedef Mixture<Transport<SpecieThermo<Thermo<EqnOfState> > > > \
Mixture##Transport##SpecieThermo##Thermo##EqnOfState; \
\
defineTemplateTypeNameAndDebugWithName \
(Mixture##Transport##SpecieThermo##Thermo##EqnOfState, \
#Mixture"<"#Transport"<"#SpecieThermo"<"#Thermo"<"#EqnOfState">>>>", 0)
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#define makeBasicRealFluidMixture(Mixture,Transport,SpecieThermo,Thermo,EqnOfState) \
\
typedef Mixture<Transport<SpecieThermo<Thermo<EqnOfState> > > > \
Mixture##Transport##SpecieThermo##Thermo##EqnOfState; \
\
defineTemplateTypeNameAndDebugWithName \
(Mixture##Transport##SpecieThermo##Thermo##EqnOfState, \
#Mixture"<"#Transport"<"#SpecieThermo"<"#Thermo"<"#EqnOfState">>>>", 0)
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

View file

@ -1,9 +1,9 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | foam-extend: Open Source CFD
\\ / O peration | Version: 3.2
\\ / A nd | Web: http://www.foam-extend.org
\\/ M anipulation | For copyright notice see file Copyright
\\ / O peration |
\\ / A nd | For copyright notice see file Copyright
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of foam-extend.
@ -48,4 +48,19 @@ Foam::basicPsiThermo::~basicPsiThermo()
{}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
const Foam::volScalarField& Foam::basicPsiThermo::drhodh() const
{
notImplemented("basicPsiThermo::drhodh()");
return const_cast<volScalarField&>(volScalarField::null());
}
const Foam::volScalarField& Foam::basicPsiThermo::drhode() const
{
notImplemented("basicPsiThermo::drhode()");
return const_cast<volScalarField&>(volScalarField::null());
}
// ************************************************************************* //

View file

@ -108,6 +108,12 @@ public:
{
return p_*psi();
}
//CL: drhodh needed for pressure equation of the real gas solver
virtual const volScalarField& drhodh() const;
//CL: drhode needed for pressure equation of the real gas solver
virtual const volScalarField& drhode() const;
};

View file

@ -58,6 +58,46 @@ addToRunTimeSelectionTable \
)
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#define makeBasicRealGasThermo(Cthermo,Mixture,Transport,SpecieThermo,Thermo,EqnOfState) \
\
typedef Cthermo<Mixture<Transport<SpecieThermo<Thermo<EqnOfState> > > > > \
Cthermo##Mixture##Transport##SpecieThermo##Thermo##EqnOfState; \
\
defineTemplateTypeNameAndDebugWithName \
( \
Cthermo##Mixture##Transport##SpecieThermo##Thermo##EqnOfState, \
#Cthermo \
"<"#Mixture"<"#Transport"<"#SpecieThermo"<"#Thermo"<"#EqnOfState">>>>>", \
0 \
); \
\
addToRunTimeSelectionTable \
( \
basicPsiThermo, \
Cthermo##Mixture##Transport##SpecieThermo##Thermo##EqnOfState, \
fvMesh \
)
#define makeBasicExternalLibraryBasedThermo(Cthermo) \
\
typedef Cthermo \
Cthermo; \
\
defineTypeNameAndDebug \
( \
Cthermo, \
0 \
); \
\
addToRunTimeSelectionTable \
( \
basicPsiThermo, \
Cthermo, \
fvMesh \
)
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif

View file

@ -111,7 +111,7 @@ Foam::hPsiThermo<MixtureType>::hPsiThermo
(
"h",
mesh.time().timeName(),
mesh,
obj,
IOobject::NO_READ,
IOobject::NO_WRITE
),

View file

@ -0,0 +1,505 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd |
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM; if not, write to the Free Software Foundation,
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Author
Christian Lucas
Institut für Thermodynamik
Technische Universität Braunschweig
Germany
\*---------------------------------------------------------------------------*/
#include "realGasEThermo.H"
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
template<class MixtureType>
void Foam::realGasEThermo<MixtureType>::calculate()
{
const scalarField& eCells = e_.internalField();
const scalarField& pCells = this->p_.internalField();
scalarField& TCells = this->T_.internalField();
scalarField& rhoCells= this->rho_.internalField();
scalarField& psiCells = this->psi_.internalField();
scalarField& drhodeCells = this->drhode_.internalField();
scalarField& muCells = this->mu_.internalField();
scalarField& alphaCells = this->alpha_.internalField();
forAll(TCells, celli)
{
const typename MixtureType::thermoType& mixture_ =
this->cellMixture(celli);
mixture_.TE(eCells[celli], TCells[celli], pCells[celli], rhoCells[celli]);
psiCells[celli]=mixture_.psiE(rhoCells[celli], TCells[celli]);
drhodeCells[celli]=mixture_.drhodE(rhoCells[celli], TCells[celli]);
muCells[celli] = mixture_.mu(TCells[celli]);
alphaCells[celli] = mixture_.alpha(rhoCells[celli], TCells[celli]);
}
forAll(T_.boundaryField(), patchi)
{
fvPatchScalarField& pp = this->p_.boundaryField()[patchi];
fvPatchScalarField& pT = this->T_.boundaryField()[patchi];
fvPatchScalarField& ppsi = this->psi_.boundaryField()[patchi];
fvPatchScalarField& pdrhode = this->drhode_.boundaryField()[patchi];
fvPatchScalarField& prho = this->rho_.boundaryField()[patchi];
fvPatchScalarField& pe = e_.boundaryField()[patchi];
fvPatchScalarField& pmu = this->mu_.boundaryField()[patchi];
fvPatchScalarField& palpha = this->alpha_.boundaryField()[patchi];
if (pT.fixesValue())
{
forAll(pT, facei)
{
const typename MixtureType::thermoType& mixture_ =
this->patchFaceMixture(patchi, facei);
prho[facei] = mixture_.rho(pp[facei], pT[facei],prho[facei]);
ppsi[facei]=mixture_.psiE(prho[facei],pT[facei]);
pdrhode[facei]=mixture_.drhodE(prho[facei],pT[facei]);
pe[facei] = mixture_.E(prho[facei], pT[facei]);
pmu[facei] = mixture_.mu(pT[facei]);
palpha[facei] = mixture_.alpha(prho[facei],pT[facei]);
}
}
else
{
forAll(pT, facei)
{
const typename MixtureType::thermoType& mixture_ =
this->patchFaceMixture(patchi, facei);
mixture_.TE(pe[facei], pT[facei],pp[facei],prho[facei]);
pmu[facei] = mixture_.mu(pT[facei]);
ppsi[facei]=mixture_.psiE(prho[facei],pT[facei]);
pdrhode[facei]=mixture_.drhodE(prho[facei],pT[facei]);
palpha[facei] = mixture_.alpha(prho[facei],pT[facei]);
}
}
}
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
template<class MixtureType>
Foam::realGasEThermo<MixtureType>::realGasEThermo
(
const fvMesh& mesh,
const objectRegistry& obj
)
:
basicPsiThermo(mesh, obj),
MixtureType(*this, mesh, obj),
e_
(
IOobject
(
"e",
mesh.time().timeName(),
obj,
IOobject::NO_READ,
IOobject::NO_WRITE
),
mesh,
dimensionSet(0, 2, -2, 0, 0),
this->eBoundaryTypes()
),
rho_
(
IOobject
(
"rhoThermo",
mesh.time().timeName(),
obj,
IOobject::READ_IF_PRESENT,
IOobject::NO_WRITE
),
mesh,
dimDensity
),
drhode_
(
IOobject
(
"drhode",
mesh.time().timeName(),
obj,
IOobject::NO_READ,
IOobject::NO_WRITE
),
mesh,
dimensionSet(1, -5, 2, 0, 0)
)
{
scalarField& eCells = e_.internalField();
const scalarField& TCells = this->T_.internalField();
const scalarField& pCells =this->p_.internalField();
scalarField& rhoCells =this->rho_.internalField();
forAll(rhoCells, celli)
{
rhoCells[celli]=this->cellMixture(celli).rho(pCells[celli],TCells[celli]);
}
forAll(rho_.boundaryField(), patchi)
{
rho_.boundaryField()[patchi] ==
rho(this->T_.boundaryField()[patchi], patchi);
}
forAll(eCells, celli)
{
eCells[celli] = this->cellMixture(celli).E(rhoCells[celli],TCells[celli]);
}
forAll(e_.boundaryField(), patchi)
{
e_.boundaryField()[patchi] ==
e(this->T_.boundaryField()[patchi], patchi);
}
this->eBoundaryCorrection(e_);
calculate();
// Switch on saving old time
this->psi_.oldTime();
}
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
template<class MixtureType>
Foam::realGasEThermo<MixtureType>::~realGasEThermo()
{}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
template<class MixtureType>
void Foam::realGasEThermo<MixtureType>::correct()
{
if (debug)
{
Info<< "entering realGasEThermo<MixtureType>::correct()" << endl;
}
// force the saving of the old-time values
this->psi_.oldTime();
calculate();
if (debug)
{
Info<< "exiting realGasEThermo<MixtureType>::correct()" << endl;
}
}
template<class MixtureType>
Foam::tmp<Foam::scalarField> Foam::realGasEThermo<MixtureType>::e
(
const scalarField& T,
const labelList& cells
) const
{
//CL: need the pressure of the internal field to calculate the realGas internal energy
//CL: this is done this way to assure compatibility to old OF Thermo-Versions
const scalarField& pCells = this->p_.internalField();
tmp<scalarField> te(new scalarField(T.size()));
scalarField& e = te();
forAll(T, celli)
{
e[celli] = this->cellMixture(cells[celli]).E(this->cellMixture(cells[celli]).rho(pCells[cells[celli]],T[celli]),T[celli]);
}
return te;
}
template<class MixtureType>
Foam::tmp<Foam::scalarField> Foam::realGasEThermo<MixtureType>::e
(
const scalarField& T,
const label patchi
) const
{
//CL: need the pressure at the patch to calculate the realGas internal energy
//CL: this is done this way to assure compatibility to old OF Thermo-Versions
const fvPatchScalarField& pp = this->p_.boundaryField()[patchi];
tmp<scalarField> te(new scalarField(T.size()));
scalarField& e = te();
forAll(T, facei)
{
e[facei] = this->patchFaceMixture(patchi, facei).E(this->patchFaceMixture(patchi, facei).rho(pp[facei], T[facei]),T[facei]);
}
return te;
}
template<class MixtureType>
Foam::tmp<Foam::scalarField> Foam::realGasEThermo<MixtureType>::rho
(
const scalarField& T,
const label patchi
) const
{
//CL: need the pressure at the patch to calculate the realGas density
//CL: this is done this way to assure compatibility to old OF Thermo-Versions
const fvPatchScalarField& pp = this->p_.boundaryField()[patchi];
tmp<scalarField> trho(new scalarField(T.size()));
scalarField& rho = trho();
forAll(T, facei)
{
rho[facei] = this->patchFaceMixture(patchi, facei).rho(pp[facei], T[facei]);
}
return trho;
}
template<class MixtureType>
Foam::tmp<Foam::scalarField> Foam::realGasEThermo<MixtureType>::Cp
(
const scalarField& T,
const label patchi
) const
{
//CL: need the pressure at the patch to calculate the realGas cp
//CL: this is done this way to assure compatibility to old OF Thermo-Versions
const fvPatchScalarField& pp = this->p_.boundaryField()[patchi];
tmp<scalarField> tCp(new scalarField(T.size()));
scalarField& cp = tCp();
forAll(T, facei)
{
cp[facei] = this->patchFaceMixture(patchi, facei).Cp(this->patchFaceMixture(patchi, facei).rho(pp[facei], T[facei]),T[facei]);
}
return tCp;
}
template<class MixtureType>
Foam::tmp<Foam::volScalarField> Foam::realGasEThermo<MixtureType>::Cp() const
{
const fvMesh& mesh = this->T_.mesh();
tmp<volScalarField> tCp
(
new volScalarField
(
IOobject
(
"Cp",
mesh.time().timeName(),
T_.db(),
IOobject::NO_READ,
IOobject::NO_WRITE
),
mesh,
dimensionSet(0, 2, -2, -1, 0)
)
);
volScalarField& cp = tCp();
forAll(this->T_, celli)
{
cp[celli] = this->cellMixture(celli).Cp(this->rho_[celli], this->T_[celli]);
}
forAll(this->T_.boundaryField(), patchi)
{
const fvPatchScalarField& pT = this->T_.boundaryField()[patchi];
const fvPatchScalarField& prho = this->rho_.boundaryField()[patchi];
fvPatchScalarField& pCp = cp.boundaryField()[patchi];
forAll(pT, facei)
{
pCp[facei] = this->patchFaceMixture(patchi, facei).Cp(prho[facei], pT[facei]);
}
}
return tCp;
}
template<class MixtureType>
Foam::tmp<Foam::scalarField> Foam::realGasEThermo<MixtureType>::Cv
(
const scalarField& T,
const label patchi
) const
{
//CL: need the pressure at the patch to calculate the realGas internal energy
//CL: this is done this way to assure compatibility to old OF Thermo-Versions
const fvPatchScalarField& pp = this->p_.boundaryField()[patchi];
tmp<scalarField> tCv(new scalarField(T.size()));
scalarField& cv = tCv();
forAll(T, facei)
{
cv[facei] = this->patchFaceMixture(patchi, facei).Cv(this->patchFaceMixture(patchi, facei).rho(pp[facei], T[facei]), T[facei]);
}
return tCv;
}
// CL: Maybe this function should be changed so that it is not "const" function anymore
template<class MixtureType>
Foam::tmp<Foam::volScalarField> Foam::realGasEThermo<MixtureType>::rho() const
{
const fvMesh& mesh = this->T_.mesh();
//CL: create an rho Field, which will be return
//CL: the problem is that this function is "const",
//CL: so a new variabel is needed
tmp<volScalarField> trho
(
new volScalarField
(
IOobject
(
"rhoFunctionThermo",
mesh.time().timeName(),
T_.db(),
IOobject::NO_READ,
IOobject::NO_WRITE
),
mesh,
dimDensity
)
);
//CL: copy "old" rho value onto the new rho field as start point
//CL: for the newton solver used in this->TE( ... )
trho()=rho_;
volScalarField& rho = trho();
const scalarField& eCells = e_.internalField();
const scalarField& pCells = this->p_.internalField();
scalarField TCells = this->T_.internalField();
forAll(pCells, celli)
{
const typename MixtureType::thermoType& mixture_ =
this->cellMixture(celli);
// getting the new rho Field
mixture_.TE(eCells[celli], TCells[celli], pCells[celli], rho[celli]);
}
forAll(p_.boundaryField(), patchi)
{
fvPatchScalarField pp = this->p_.boundaryField()[patchi];
fvPatchScalarField pe = e_.boundaryField()[patchi];
fvPatchScalarField pT = this->T_.boundaryField()[patchi];
fvPatchScalarField& prho_ = rho.boundaryField()[patchi];
forAll(pp, facei)
{
const typename MixtureType::thermoType& mixture_ =
this->patchFaceMixture(patchi, facei);
// getting the new rho patch Field
mixture_.TE(pe[facei], pT[facei],pp[facei],prho_[facei]);
}
}
return trho;
}
template<class MixtureType>
Foam::tmp<Foam::volScalarField> Foam::realGasEThermo<MixtureType>::Cv() const
{
const fvMesh& mesh = this->T_.mesh();
tmp<volScalarField> tCv
(
new volScalarField
(
IOobject
(
"Cv",
mesh.time().timeName(),
T_.db(),
IOobject::NO_READ,
IOobject::NO_WRITE
),
mesh,
dimensionSet(0, 2, -2, -1, 0)
)
);
volScalarField& cv = tCv();
forAll(this->T_, celli)
{
cv[celli] = this->cellMixture(celli).Cv(this->rho_[celli], this->T_[celli]);
}
forAll(this->T_.boundaryField(), patchi)
{
cv.boundaryField()[patchi] =
Cv(this->T_.boundaryField()[patchi], patchi);
}
return tCv;
}
template<class MixtureType>
bool Foam::realGasEThermo<MixtureType>::read()
{
if (basicPsiThermo::read())
{
MixtureType::read(*this);
return true;
}
else
{
return false;
}
}
// ************************************************************************* //

View file

@ -0,0 +1,205 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | .
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM; if not, write to the Free Software Foundation,
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Class
Foam::realGasEThermo
Description
Internal energy for a real gas fluid libary
SourceFiles
realGasEThermo.C
Author
Christian Lucas
Institut für Thermodynamik
Technische Universität Braunschweig
Germany
\*---------------------------------------------------------------------------*/
#ifndef realGasEThermo_H
#define realGasEThermo_H
#include "basicPsiThermo.H"
#include "basicMixture.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
/*---------------------------------------------------------------------------*\
Class realGasEThermo Declaration
\*---------------------------------------------------------------------------*/
template<class MixtureType>
class realGasEThermo
:
public basicPsiThermo,
public MixtureType
{
// Private data
//- Enthalpy field
volScalarField e_;
//- Density field
volScalarField rho_;
//- drhode_Field
volScalarField drhode_;
// Private member functions
//- Calculate the thermo variables
void calculate();
//- Construct as copy (not implemented)
realGasEThermo(const realGasEThermo<MixtureType>&);
public:
//- Runtime type information
TypeName("realGasEThermo");
// Constructors
//- Construct from mesh and object registry
realGasEThermo(const fvMesh&, const objectRegistry&);
//- Destructor
virtual ~realGasEThermo();
// Member functions
//- Return the compostion of the mixture
virtual basicMixture& composition()
{
return *this;
}
//- Return the compostion of the mixture
virtual const basicMixture& composition() const
{
return *this;
}
//- Update properties
virtual void correct();
// Access to thermodynamic state variables
//- Internal energy [J/kg]
// Non-const access allowed for transport equations
virtual volScalarField& e()
{
return e_;
}
//- Internal energy [J/kg]
virtual const volScalarField& e() const
{
return e_;
}
//CL: drhode needed for pressure equation of the real gas solver
virtual const volScalarField& drhode() const
{
return drhode_;
}
// Fields derived from thermodynamic state variables
//- Internal energy for cell-set [J/kg]
virtual tmp<scalarField> e
(
const scalarField& T,
const labelList& cells
) const;
//- Internal energy for patch [J/kg]
virtual tmp<scalarField> e
(
const scalarField& T,
const label patchi
) const;
//- Density for patch [J/kg]
virtual tmp<scalarField> rho
(
const scalarField& T,
const label patchi
) const;
//- Heat capacity at constant pressure for patch [J/kg/K]
virtual tmp<scalarField> Cp
(
const scalarField& T,
const label patchi
) const;
//- Heat capacity at constant pressure [J/kg/K]
virtual tmp<volScalarField> Cp() const;
//- Heat capacity at constant volume for patch [J/kg/K]
virtual tmp<scalarField> Cv
(
const scalarField& T,
const label patchi
) const;
//- Heat capacity at constant volume [J/kg/K]
virtual tmp<volScalarField> Cv() const;
//- Density [kg/m^3] - uses current value of pressure
virtual tmp<volScalarField> rho() const;
//- Read thermophysicalProperties dictionary
virtual bool read();
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
#ifdef NoRepository
# include "realGasEThermo.C"
#endif
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View file

@ -0,0 +1,221 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd |
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM; if not, write to the Free Software Foundation,
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Author
Christian Lucas
Institut für Thermodynamik
Technische Universität Braunschweig
Germany
\*---------------------------------------------------------------------------*/
#include "makeBasicPsiThermo.H"
#include "redlichKwong.H"
#include "pengRobinson.H"
#include "aungierRedlichKwong.H"
#include "soaveRedlichKwong.H"
#include "nasaHeatCapacityPolynomial.H"
#include "realGasSpecieThermo.H"
#include "constTransport.H"
#include "sutherlandTransport.H"
#include "constantHeatCapacity.H"
#include "pureMixture.H"
#include "realGasEThermo.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
/* * * * * * * * * * * * * * * private static data * * * * * * * * * * * * * */
makeBasicRealGasThermo
(
realGasEThermo,
pureMixture,
sutherlandTransport,
realGasSpecieThermo,
nasaHeatCapacityPolynomial,
pengRobinson
);
makeBasicRealGasThermo
(
realGasEThermo,
pureMixture,
sutherlandTransport,
realGasSpecieThermo,
nasaHeatCapacityPolynomial,
aungierRedlichKwong
);
makeBasicRealGasThermo
(
realGasEThermo,
pureMixture,
sutherlandTransport,
realGasSpecieThermo,
nasaHeatCapacityPolynomial,
redlichKwong
);
makeBasicRealGasThermo
(
realGasEThermo,
pureMixture,
sutherlandTransport,
realGasSpecieThermo,
nasaHeatCapacityPolynomial,
soaveRedlichKwong
);
makeBasicRealGasThermo
(
realGasEThermo,
pureMixture,
constTransport,
realGasSpecieThermo,
nasaHeatCapacityPolynomial,
pengRobinson
);
makeBasicRealGasThermo
(
realGasEThermo,
pureMixture,
constTransport,
realGasSpecieThermo,
nasaHeatCapacityPolynomial,
aungierRedlichKwong
);
makeBasicRealGasThermo
(
realGasEThermo,
pureMixture,
constTransport,
realGasSpecieThermo,
nasaHeatCapacityPolynomial,
redlichKwong
);
makeBasicRealGasThermo
(
realGasEThermo,
pureMixture,
constTransport,
realGasSpecieThermo,
nasaHeatCapacityPolynomial,
soaveRedlichKwong
);
makeBasicRealGasThermo
(
realGasEThermo,
pureMixture,
sutherlandTransport,
realGasSpecieThermo,
constantHeatCapacity,
pengRobinson
);
makeBasicRealGasThermo
(
realGasEThermo,
pureMixture,
sutherlandTransport,
realGasSpecieThermo,
constantHeatCapacity,
aungierRedlichKwong
);
makeBasicRealGasThermo
(
realGasEThermo,
pureMixture,
sutherlandTransport,
realGasSpecieThermo,
constantHeatCapacity,
redlichKwong
);
makeBasicRealGasThermo
(
realGasEThermo,
pureMixture,
sutherlandTransport,
realGasSpecieThermo,
constantHeatCapacity,
soaveRedlichKwong
);
makeBasicRealGasThermo
(
realGasEThermo,
pureMixture,
constTransport,
realGasSpecieThermo,
constantHeatCapacity,
pengRobinson
);
makeBasicRealGasThermo
(
realGasEThermo,
pureMixture,
constTransport,
realGasSpecieThermo,
constantHeatCapacity,
aungierRedlichKwong
);
makeBasicRealGasThermo
(
realGasEThermo,
pureMixture,
constTransport,
realGasSpecieThermo,
constantHeatCapacity,
redlichKwong
);
makeBasicRealGasThermo
(
realGasEThermo,
pureMixture,
constTransport,
realGasSpecieThermo,
constantHeatCapacity,
soaveRedlichKwong
);
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// ************************************************************************* //

View file

@ -0,0 +1,505 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd |
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM; if not, write to the Free Software Foundation,
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Author
Christian Lucas
Institut für Thermodynamik
Technische Universität Braunschweig
Germany
\*---------------------------------------------------------------------------*/
#include "realGasHThermo.H"
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
template<class MixtureType>
void Foam::realGasHThermo<MixtureType>::calculate()
{
const scalarField& hCells = h_.internalField();
const scalarField& pCells = this->p_.internalField();
scalarField& TCells = this->T_.internalField();
scalarField& rhoCells= this->rho_.internalField();
scalarField& psiCells = this->psi_.internalField();
scalarField& drhodhCells = this->drhodh_.internalField();
scalarField& muCells = this->mu_.internalField();
scalarField& alphaCells = this->alpha_.internalField();
forAll(TCells, celli)
{
const typename MixtureType::thermoType& mixture_ =
this->cellMixture(celli);
mixture_.TH(hCells[celli], TCells[celli], pCells[celli], rhoCells[celli]);
psiCells[celli] = mixture_.psi(rhoCells[celli], TCells[celli]);
drhodhCells[celli] = mixture_.drhodH(rhoCells[celli], TCells[celli]);
muCells[celli] = mixture_.mu(TCells[celli]);
alphaCells[celli] = mixture_.alpha(rhoCells[celli], TCells[celli]);
}
forAll(T_.boundaryField(), patchi)
{
fvPatchScalarField& pp = this->p_.boundaryField()[patchi];
fvPatchScalarField& pT = this->T_.boundaryField()[patchi];
fvPatchScalarField& ppsi = this->psi_.boundaryField()[patchi];
fvPatchScalarField& pdrhodh = this->drhodh_.boundaryField()[patchi];
fvPatchScalarField& prho = this->rho_.boundaryField()[patchi];
fvPatchScalarField& ph = h_.boundaryField()[patchi];
fvPatchScalarField& pmu = this->mu_.boundaryField()[patchi];
fvPatchScalarField& palpha = this->alpha_.boundaryField()[patchi];
if (pT.fixesValue())
{
forAll(pT, facei)
{
const typename MixtureType::thermoType& mixture_ =
this->patchFaceMixture(patchi, facei);
prho[facei] = mixture_.rho(pp[facei], pT[facei],prho[facei]);
ppsi[facei]=mixture_.psi(prho[facei],pT[facei]);
pdrhodh[facei]=mixture_.drhodH(prho[facei],pT[facei]);
ph[facei] = mixture_.H(prho[facei], pT[facei]);
pmu[facei] = mixture_.mu(pT[facei]);
palpha[facei] = mixture_.alpha(prho[facei],pT[facei]);
}
}
else
{
forAll(pT, facei)
{
const typename MixtureType::thermoType& mixture_ =
this->patchFaceMixture(patchi, facei);
mixture_.TH(ph[facei], pT[facei],pp[facei],prho[facei]);
pmu[facei] = mixture_.mu(pT[facei]);
ppsi[facei]=mixture_.psi(prho[facei],pT[facei]);
pdrhodh[facei]=mixture_.drhodH(prho[facei],pT[facei]);
palpha[facei] = mixture_.alpha(prho[facei],pT[facei]);
}
}
}
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
template<class MixtureType>
Foam::realGasHThermo<MixtureType>::realGasHThermo
(
const fvMesh& mesh,
const objectRegistry& obj
)
:
basicPsiThermo(mesh, obj),
MixtureType(*this, mesh, obj),
h_
(
IOobject
(
"h",
mesh.time().timeName(),
obj,
IOobject::NO_READ,
IOobject::NO_WRITE
),
mesh,
dimensionSet(0, 2, -2, 0, 0),
this->hBoundaryTypes()
),
rho_
(
IOobject
(
"rhoThermo",
mesh.time().timeName(),
obj,
IOobject::READ_IF_PRESENT,
IOobject::NO_WRITE
),
mesh,
dimDensity
),
drhodh_
(
IOobject
(
"drhodh",
mesh.time().timeName(),
obj,
IOobject::NO_READ,
IOobject::NO_WRITE
),
mesh,
dimensionSet(1, -5, 2, 0, 0)
)
{
scalarField& hCells = h_.internalField();
const scalarField& TCells = this->T_.internalField();
const scalarField& pCells =this->p_.internalField();
scalarField& rhoCells =this->rho_.internalField();
forAll(rhoCells, celli)
{
rhoCells[celli]=this->cellMixture(celli).rho(pCells[celli],TCells[celli]);
}
forAll(rho_.boundaryField(), patchi)
{
rho_.boundaryField()[patchi] ==
rho(this->T_.boundaryField()[patchi], patchi);
}
forAll(hCells, celli)
{
hCells[celli] = this->cellMixture(celli).H(rhoCells[celli],TCells[celli]);
}
forAll(h_.boundaryField(), patchi)
{
h_.boundaryField()[patchi] ==
h(this->T_.boundaryField()[patchi], patchi);
}
hBoundaryCorrection(h_);
calculate();
// Switch on saving old time
this->psi_.oldTime();
}
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
template<class MixtureType>
Foam::realGasHThermo<MixtureType>::~realGasHThermo()
{}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
template<class MixtureType>
void Foam::realGasHThermo<MixtureType>::correct()
{
if (debug)
{
Info<< "entering realGasHThermo<MixtureType>::correct()" << endl;
}
// force the saving of the old-time values
this->psi_.oldTime();
calculate();
if (debug)
{
Info<< "exiting realGasHThermo<MixtureType>::correct()" << endl;
}
}
template<class MixtureType>
Foam::tmp<Foam::scalarField> Foam::realGasHThermo<MixtureType>::h
(
const scalarField& T,
const labelList& cells
) const
{
//CL: need the pressure of the internal field to calculate the realGas enthalpy
//CL: this is done this way to assure compatibility to old OF Thermo-Versions
const scalarField& pCells = this->p_.internalField();
tmp<scalarField> th(new scalarField(T.size()));
scalarField& h = th();
forAll(T, celli)
{
h[celli] = this->cellMixture(cells[celli]).H(this->cellMixture(cells[celli]).rho(pCells[cells[celli]],T[celli]),T[celli]);
}
return th;
}
template<class MixtureType>
Foam::tmp<Foam::scalarField> Foam::realGasHThermo<MixtureType>::h
(
const scalarField& T,
const label patchi
) const
{
//CL: need the pressure at the patch to calculate the realGas enthalpy
//CL: this is done this way to assure compatibility to old OF Thermo-Versions
const fvPatchScalarField& pp = this->p_.boundaryField()[patchi];
tmp<scalarField> th(new scalarField(T.size()));
scalarField& h = th();
forAll(T, facei)
{
h[facei] = this->patchFaceMixture(patchi, facei).H(this->patchFaceMixture(patchi, facei).rho(pp[facei], T[facei]),T[facei]);
}
return th;
}
template<class MixtureType>
Foam::tmp<Foam::scalarField> Foam::realGasHThermo<MixtureType>::rho
(
const scalarField& T,
const label patchi
) const
{
//CL: need the pressure at the patch to calculate the realGas enthalpy
//CL: this is done this way to assure compatibility to old OF Thermo-Versions
const fvPatchScalarField& pp = this->p_.boundaryField()[patchi];
tmp<scalarField> trho(new scalarField(T.size()));
scalarField& rho = trho();
forAll(T, facei)
{
rho[facei] = this->patchFaceMixture(patchi, facei).rho(pp[facei], T[facei]);
}
return trho;
}
template<class MixtureType>
Foam::tmp<Foam::scalarField> Foam::realGasHThermo<MixtureType>::Cp
(
const scalarField& T,
const label patchi
) const
{
//CL: need the pressure at the patch to calculate the realGas enthalpy
//CL: this is done this way to assure compatibility to old OF Thermo-Versions
const fvPatchScalarField& pp = this->p_.boundaryField()[patchi];
tmp<scalarField> tCp(new scalarField(T.size()));
scalarField& cp = tCp();
forAll(T, facei)
{
cp[facei] = this->patchFaceMixture(patchi, facei).Cp(this->patchFaceMixture(patchi, facei).rho(pp[facei], T[facei]),T[facei]);
}
return tCp;
}
template<class MixtureType>
Foam::tmp<Foam::volScalarField> Foam::realGasHThermo<MixtureType>::Cp() const
{
const fvMesh& mesh = this->T_.mesh();
tmp<volScalarField> tCp
(
new volScalarField
(
IOobject
(
"Cp",
mesh.time().timeName(),
this->T_.db(),
IOobject::NO_READ,
IOobject::NO_WRITE
),
mesh,
dimensionSet(0, 2, -2, -1, 0)
)
);
volScalarField& cp = tCp();
forAll(this->T_, celli)
{
cp[celli] = this->cellMixture(celli).Cp(this->rho_[celli], this->T_[celli]);
}
forAll(this->T_.boundaryField(), patchi)
{
const fvPatchScalarField& pT = this->T_.boundaryField()[patchi];
const fvPatchScalarField& prho = this->rho_.boundaryField()[patchi];
fvPatchScalarField& pCp = cp.boundaryField()[patchi];
forAll(pT, facei)
{
pCp[facei] = this->patchFaceMixture(patchi, facei).Cp(prho[facei], pT[facei]);
}
}
return tCp;
}
template<class MixtureType>
Foam::tmp<Foam::scalarField> Foam::realGasHThermo<MixtureType>::Cv
(
const scalarField& T,
const label patchi
) const
{
//CL: need the pressure at the patch to calculate the realGas enthalpy
//CL: this is done this way to assure compatibility to old OF Thermo-Versions
const fvPatchScalarField& pp = this->p_.boundaryField()[patchi];
tmp<scalarField> tCv(new scalarField(T.size()));
scalarField& cv = tCv();
forAll(T, facei)
{
cv[facei] = this->patchFaceMixture(patchi, facei).Cv(this->patchFaceMixture(patchi, facei).rho(pp[facei], T[facei]), T[facei]);
}
return tCv;
}
// CL: Maybe this function should be changed so that it is not "const" fucntion anymore
template<class MixtureType>
Foam::tmp<Foam::volScalarField> Foam::realGasHThermo<MixtureType>::rho() const
{
const fvMesh& mesh = this->T_.mesh();
//CL: create a rho Field, which will be return
//CL: the problem is that this function is "const",
//CL: so a new variabel is needed
tmp<volScalarField> trho
(
new volScalarField
(
IOobject
(
"rhoFunctionThermo",
mesh.time().timeName(),
this->T_.db(),
IOobject::NO_READ,
IOobject::NO_WRITE
),
mesh,
dimDensity
)
);
//CL: copy "old" rho value onto the new rho field as start point
//CL: for the newton solver used in this->TH( ... )
trho()=rho_;
volScalarField& rho = trho();
const scalarField& hCells = h_.internalField();
const scalarField& pCells = this->p_.internalField();
scalarField TCells = this->T_.internalField();
forAll(pCells, celli)
{
const typename MixtureType::thermoType& mixture_ =
this->cellMixture(celli);
// getting the new rho Field
mixture_.TH(hCells[celli], TCells[celli], pCells[celli], rho[celli]);
}
forAll(p_.boundaryField(), patchi)
{
fvPatchScalarField pp = this->p_.boundaryField()[patchi];
fvPatchScalarField ph = h_.boundaryField()[patchi];
fvPatchScalarField pT = this->T_.boundaryField()[patchi];
fvPatchScalarField& prho_ = rho.boundaryField()[patchi];
forAll(pp, facei)
{
const typename MixtureType::thermoType& mixture_ =
this->patchFaceMixture(patchi, facei);
// getting the new rho patch Field
mixture_.TH(ph[facei], pT[facei],pp[facei],prho_[facei]);
}
}
return trho;
}
template<class MixtureType>
Foam::tmp<Foam::volScalarField> Foam::realGasHThermo<MixtureType>::Cv() const
{
const fvMesh& mesh = this->T_.mesh();
tmp<volScalarField> tCv
(
new volScalarField
(
IOobject
(
"Cv",
mesh.time().timeName(),
this->T_.db(),
IOobject::NO_READ,
IOobject::NO_WRITE
),
mesh,
dimensionSet(0, 2, -2, -1, 0)
)
);
volScalarField& cv = tCv();
forAll(this->T_, celli)
{
cv[celli] = this->cellMixture(celli).Cv(this->rho_[celli], this->T_[celli]);
}
forAll(this->T_.boundaryField(), patchi)
{
cv.boundaryField()[patchi] =
Cv(this->T_.boundaryField()[patchi], patchi);
}
return tCv;
}
template<class MixtureType>
bool Foam::realGasHThermo<MixtureType>::read()
{
if (basicPsiThermo::read())
{
MixtureType::read(*this);
return true;
}
else
{
return false;
}
}
// ************************************************************************* //

View file

@ -0,0 +1,205 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | .
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM; if not, write to the Free Software Foundation,
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Class
Foam::realGasHThermo
Description
Enthalpy for a real gas fluid libary
SourceFiles
realGasHThermo.C
Author
Christian Lucas
Institut für Thermodynamik
Technische Universität Braunschweig
Germany
\*---------------------------------------------------------------------------*/
#ifndef realGasHThermo_H
#define realGasHThermo_H
#include "basicPsiThermo.H"
#include "basicMixture.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
/*---------------------------------------------------------------------------*\
Class realGasHThermo Declaration
\*---------------------------------------------------------------------------*/
template<class MixtureType>
class realGasHThermo
:
public basicPsiThermo,
public MixtureType
{
// Private data
//- Enthalpy field
volScalarField h_;
//- DensityField
volScalarField rho_;
//- drhodh_Field
volScalarField drhodh_;
// Private member functions
//- Calculate the thermo variables
void calculate();
//- Construct as copy (not implemented)
realGasHThermo(const realGasHThermo<MixtureType>&);
public:
//- Runtime type information
TypeName("realGasHThermo");
// Constructors
//- Construct from mesh
realGasHThermo(const fvMesh&, const objectRegistry& obj);
//- Destructor
virtual ~realGasHThermo();
// Member functions
//- Return the compostion of the mixture
virtual basicMixture& composition()
{
return *this;
}
//- Return the compostion of the mixture
virtual const basicMixture& composition() const
{
return *this;
}
//- Update properties
virtual void correct();
// Access to thermodynamic state variables
//- Enthalpy [J/kg]
// Non-const access allowed for transport equations
virtual volScalarField& h()
{
return h_;
}
//- Enthalpy [J/kg]
virtual const volScalarField& h() const
{
return h_;
}
//CL: drhodh needed for pressure equation of the real gas solver
virtual const volScalarField& drhodh() const
{
return drhodh_;
}
// Fields derived from thermodynamic state variables
//- Enthalpy for cell-set [J/kg]
virtual tmp<scalarField> h
(
const scalarField& T,
const labelList& cells
) const;
//- Enthalpy for patch [J/kg]
virtual tmp<scalarField> h
(
const scalarField& T,
const label patchi
) const;
//- Density for patch [J/kg]
virtual tmp<scalarField> rho
(
const scalarField& T,
const label patchi
) const;
//- Heat capacity at constant pressure for patch [J/kg/K]
virtual tmp<scalarField> Cp
(
const scalarField& T,
const label patchi
) const;
//- Heat capacity at constant pressure [J/kg/K]
virtual tmp<volScalarField> Cp() const;
//- Heat capacity at constant volume for patch [J/kg/K]
virtual tmp<scalarField> Cv
(
const scalarField& T,
const label patchi
) const;
//- Heat capacity at constant volume [J/kg/K]
virtual tmp<volScalarField> Cv() const;
//- Density [kg/m^3] - uses current value of pressure
virtual tmp<volScalarField> rho() const;
//- Read thermophysicalProperties dictionary
virtual bool read();
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
#ifdef NoRepository
# include "realGasHThermo.C"
#endif
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View file

@ -0,0 +1,221 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd |
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM; if not, write to the Free Software Foundation,
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Author
Christian Lucas
Institut für Thermodynamik
Technische Universität Braunschweig
Germany
\*---------------------------------------------------------------------------*/
#include "makeBasicPsiThermo.H"
#include "redlichKwong.H"
#include "pengRobinson.H"
#include "aungierRedlichKwong.H"
#include "soaveRedlichKwong.H"
#include "nasaHeatCapacityPolynomial.H"
#include "realGasSpecieThermo.H"
#include "constTransport.H"
#include "sutherlandTransport.H"
#include "constantHeatCapacity.H"
#include "pureMixture.H"
#include "realGasHThermo.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
/* * * * * * * * * * * * * * * private static data * * * * * * * * * * * * * */
makeBasicRealGasThermo
(
realGasHThermo,
pureMixture,
sutherlandTransport,
realGasSpecieThermo,
nasaHeatCapacityPolynomial,
pengRobinson
);
makeBasicRealGasThermo
(
realGasHThermo,
pureMixture,
sutherlandTransport,
realGasSpecieThermo,
nasaHeatCapacityPolynomial,
aungierRedlichKwong
);
makeBasicRealGasThermo
(
realGasHThermo,
pureMixture,
sutherlandTransport,
realGasSpecieThermo,
nasaHeatCapacityPolynomial,
redlichKwong
);
makeBasicRealGasThermo
(
realGasHThermo,
pureMixture,
sutherlandTransport,
realGasSpecieThermo,
nasaHeatCapacityPolynomial,
soaveRedlichKwong
);
makeBasicRealGasThermo
(
realGasHThermo,
pureMixture,
constTransport,
realGasSpecieThermo,
nasaHeatCapacityPolynomial,
pengRobinson
);
makeBasicRealGasThermo
(
realGasHThermo,
pureMixture,
constTransport,
realGasSpecieThermo,
nasaHeatCapacityPolynomial,
aungierRedlichKwong
);
makeBasicRealGasThermo
(
realGasHThermo,
pureMixture,
constTransport,
realGasSpecieThermo,
nasaHeatCapacityPolynomial,
redlichKwong
);
makeBasicRealGasThermo
(
realGasHThermo,
pureMixture,
constTransport,
realGasSpecieThermo,
nasaHeatCapacityPolynomial,
soaveRedlichKwong
);
makeBasicRealGasThermo
(
realGasHThermo,
pureMixture,
sutherlandTransport,
realGasSpecieThermo,
constantHeatCapacity,
pengRobinson
);
makeBasicRealGasThermo
(
realGasHThermo,
pureMixture,
sutherlandTransport,
realGasSpecieThermo,
constantHeatCapacity,
aungierRedlichKwong
);
makeBasicRealGasThermo
(
realGasHThermo,
pureMixture,
sutherlandTransport,
realGasSpecieThermo,
constantHeatCapacity,
redlichKwong
);
makeBasicRealGasThermo
(
realGasHThermo,
pureMixture,
sutherlandTransport,
realGasSpecieThermo,
constantHeatCapacity,
soaveRedlichKwong
);
makeBasicRealGasThermo
(
realGasHThermo,
pureMixture,
constTransport,
realGasSpecieThermo,
constantHeatCapacity,
pengRobinson
);
makeBasicRealGasThermo
(
realGasHThermo,
pureMixture,
constTransport,
realGasSpecieThermo,
constantHeatCapacity,
aungierRedlichKwong
);
makeBasicRealGasThermo
(
realGasHThermo,
pureMixture,
constTransport,
realGasSpecieThermo,
constantHeatCapacity,
redlichKwong
);
makeBasicRealGasThermo
(
realGasHThermo,
pureMixture,
constTransport,
realGasSpecieThermo,
constantHeatCapacity,
soaveRedlichKwong
);
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// ************************************************************************* //

View file

@ -8,6 +8,10 @@ $(atomicWeights)/atomicWeights.C
$(specie)/specie.C
$(speciesTable)/speciesTable.C
$(equationOfState)/perfectGas/perfectGas.C
$(equationOfState)/cubicEquationOfState/redlichKwong/redlichKwong.C
$(equationOfState)/cubicEquationOfState/aungierRedlichKwong/aungierRedlichKwong.C
$(equationOfState)/cubicEquationOfState/pengRobinson/pengRobinson.C
$(equationOfState)/cubicEquationOfState/soaveRedlichKwong/soaveRedlichKwong.C
$(reactions)/makeChemkinReactions.C
$(reactions)/makeReactionThermoReactions.C
$(reactions)/makeLangmuirHinshelwoodReactions.C

View file

@ -0,0 +1,137 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright held by original author
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM; if not, write to the Free Software Foundation,
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Description
Aungier Redlich Kwong equation of state.
Author
Christian Lucas
Institut für Thermodynamik
Technische Universität Braunschweig
Germany
\*---------------------------------------------------------------------------*/
#include "aungierRedlichKwong.H"
#include "IOstreams.H"
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::aungierRedlichKwong::aungierRedlichKwong(Istream& is)
:
specie(is),
pcrit_(readScalar(is)),
Tcrit_(readScalar(is)),
rhocrit_(readScalar(is)),
azentricFactor_(readScalar(is)),
a0_(0.42747*pow(this->RR(), 2)*pow(Tcrit_, 2)/pcrit_),
b_(0.08664*this->RR()*Tcrit_/pcrit_),
c_(this->RR()*Tcrit_/(pcrit_+(a0_/(this->W()/rhocrit_*(this->W()/rhocrit_ + b_)))) + b_ - this->W()/rhocrit_),
n_(0.4986 + 1.2735*azentricFactor_ + 0.4754*pow(azentricFactor_, 2)),
b2_(b_*b_),
b3_(b2_*b_),
b4_(b3_*b_),
b5_(b4_*b_),
c2_(c_*c_),
//CL: Only uses the default values
rhoMin_(1e-3),
rhoMax_(1500),
// Starting GUESS for the density by ideal gas law
rhostd_(this->rho(this->Pstd(), this->Tstd(), this->Pstd()/(this->Tstd()*this->R()))),
aSave(0.0),
daSave(0.0),
d2aSave(0.0),
TSave(0.0)
{
is.check("aungierRedlichKwong::aungierRedlichKwong(Istream& is)");
}
//CL: Constructed needed in OpenFOAM 2.x.x
//CL: Code works fine, but compiling problem in OpenFOAM 1.6.ext
//CL: because specie has no constructor using dict
/*
Foam::aungierRedlichKwong::aungierRedlichKwong(const dictionary& dict)
:
specie(dict),
pcrit_(readScalar(dict.subDict("equationOfState").lookup("pCritical"))),
Tcrit_(readScalar(dict.subDict("equationOfState").lookup("TCritical"))),
rhocrit_(readScalar(dict.subDict("equationOfState").lookup("rhoCritical"))),
azentricFactor_(readScalar(dict.subDict("equationOfState").lookup("azentricFactor"))),
a0_(0.42747*pow(this->RR(), 2)*pow(Tcrit_, 2)/pcrit_),
b_(0.08664*this->RR()*Tcrit_/pcrit_),
c_(this->RR()*Tcrit_/(pcrit_+(a0_/(this->W()/rhocrit_*(this->W()/rhocrit_+b_))))+b_-this->W()/rhocrit_),
n_(0.4986+1.2735*azentricFactor_+0.4754*pow(azentricFactor_,2)),
b2_(b_*b_),
b3_(b2_*b_),
b4_(b3_*b_),
b5_(b4_*b_),
c2_(pow(c_,2)),
//CL: rhoMin and rhoMax are only used as boundaries for the bisection method (see rho function)
//CL: important: rhoMin and rhoMax are not used as boundary for the newton solver
//CL: therefore, rho can be larger than rhoMax and smaller than rhoMin
rhoMin_(dict.subDict("equationOfState").lookupOrDefault("rhoMin",1e-3)),
rhoMax_(dict.subDict("equationOfState").lookupOrDefault("rhoMax",1500)),
// Starting GUESS for the density by ideal gas law
rhostd_(this->rho(this->Pstd(), this->Tstd(), this->Pstd()/(this->Tstd()*this->R()))),
aSave(0.0),
daSave(0.0),
d2aSave(0.0),
TSave(0.0)
{
is.check("aungierRedlichKwong::aungierRedlichKwong(Istream& is)");
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
void Foam::aungierRedlichKwong::write(Ostream& os) const
{
specie::write(os);
dictionary dict("equationOfState");
dict.add("pCritical", pcrit_);
dict.add("TCritical", Tcrit_);
dict.add("azentricFactor", azentricFactor_);
dict.add("rhoCritical", rhocrit_);
dict.add("rhoMin", rhoMin_);
dict.add("rhoMax", rhoMax_);
os << indent << dict.dictName() << dict;
}
*/
// * * * * * * * * * * * * * * * Ostream Operator * * * * * * * * * * * * * //
Foam::Ostream& Foam::operator<<(Ostream& os, const aungierRedlichKwong& ark)
{
os << static_cast<const specie&>(ark)<< token::SPACE
<< ark.pcrit_ << tab<< ark.Tcrit_<< tab<<ark.azentricFactor_<< tab<<ark.rhocrit_;
os.check("Ostream& operator<<(Ostream& os, const aungierRedlichKwong& st)");
return os;
}
// ************************************************************************* //

View file

@ -0,0 +1,285 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright held by original author
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM; if not, write to the Free Software Foundation,
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Class
Foam::aungierRedlichKwong
Description
Aungier Redlich Kwong equation of state.
Paper:
Title: A Fast, Accurate Real Gas Equation of State for Fluid Dynamic Analysis Applications
Authors: R. H. Aungier
Journal: Journal of Fluids Engineering, Vol.117, 1995
SourceFiles
aungierRedlichKwongI.H
aungierRedlichKwong.C
Author
Christian Lucas
Institut für Thermodynamik
Technische Universität Braunschweig
Germany
\*---------------------------------------------------------------------------*/
#ifndef aungierRedlichKwong_H
#define aungierRedlichKwong_H
#include "specie.H"
#include "autoPtr.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
/*---------------------------------------------------------------------------*\
Class aungierRedlichKwong Declaration
\*---------------------------------------------------------------------------*/
class aungierRedlichKwong
:
public specie
{
// private data
//CL: data at critical point
scalar pcrit_;
scalar Tcrit_;
scalar rhocrit_;
scalar azentricFactor_;
//Aungier Redlich Kwong factors
scalar a0_;
scalar b_;
scalar c_;
scalar n_;
//CL: pow of constants (b_, c_) used in the code e.g. b2_=b*b;
scalar b2_;
scalar b3_;
scalar b4_;
scalar b5_;
scalar c2_;
//CL: rhoMin and rhoMax are only used as boundaries for the bisection methode (see rho function)
scalar rhoMin_;
scalar rhoMax_;
//- Density @STD, initialise after a0, b, c, n!
scalar rhostd_;
//CL: Variables to save the values of a, dadT and d2adT2 of the mixture
//CL: Variables must corrected for changing temperatures
mutable scalar aSave;
mutable scalar daSave;
mutable scalar d2aSave;
//CL: save the temperature for which the save coefficients (amix,dadTmix,d2adT2mix) are correct
mutable scalar TSave;
//Protected functions
//CL: function updates the coefficients (aSave, daSave, d2aSave)
inline void updateModelCoefficients(const scalar T) const;
public:
// Constructors
//- Construct from components
inline aungierRedlichKwong
(
const specie& sp
);
//- Construct from Istream
aungierRedlichKwong(Istream&);
//- Construct from dictionary
//aungierRedlichKwong(const dictionary& dict);
//- Construct as named copy
inline aungierRedlichKwong(const word& name, const aungierRedlichKwong&);
//- Construct and return a clone
inline autoPtr<aungierRedlichKwong> clone() const;
// Selector from Istream
inline static autoPtr<aungierRedlichKwong> New(Istream& is);
// Member functions
//Return Aungier Redlich Kwong factors
inline scalar a0() const;
inline scalar b() const;
inline scalar c() const;
inline scalar n() const;
inline scalar rhostd() const;
inline scalar rhoMin() const;
inline scalar rhoMax() const;
inline scalar Tcrit() const;
inline scalar pcrit() const;
inline scalar rhocrit() const;
inline scalar azentricFactor() const;
//CL: Model coefficient a(T)
inline scalar a(const scalar T) const;
//CL: temperature deriviative of model coefficient a(T)
inline scalar dadT(const scalar T) const;
//CL: second order temperature deriviative of model coefficient a(T)
inline scalar d2adT2(const scalar T) const;
//CL: Equation of state
inline scalar p(const scalar rho, const scalar T) const;
//CL: first order derivatives
inline scalar dpdv(const scalar rho, const scalar T) const;
inline scalar dpdT(const scalar rho, const scalar T) const;
inline scalar dvdT(const scalar rho, const scalar T) const;
inline scalar dvdp(const scalar rho, const scalar T) const;
inline scalar isobarExpCoef(const scalar rho, const scalar T) const;
inline scalar isothermalCompressiblity
(
const scalar rho,
const scalar T
) const;
//CL: Used for cv
inline scalar integral_d2pdT2_dv
(
const scalar rho,
const scalar T
) const;
//CL: second order derivatives, not Used At The Moment
inline scalar d2pdv2(const scalar rho, const scalar T) const;
inline scalar d2pdT2(const scalar rho, const scalar T) const;
inline scalar d2pdvdT(const scalar rho, const scalar T) const;
inline scalar d2vdT2(const scalar rho, const scalar T) const;
//CL: Used for internal Energy
inline scalar integral_p_dv
(
const scalar rho,
const scalar T
) const;
//CL: Used for Entropy
inline scalar integral_dpdT_dv
(
const scalar rho,
const scalar T
) const;
//- Return density [kg/m^3]
// rho0 is the starting point of the newton solver used to calculate rho
inline scalar rho
(
const scalar p,
const scalar T,
const scalar rho0
) const;
inline scalar rho(const scalar p, const scalar T) const;
//- Return compressibility drho/dp at T=constant [s^2/m^2]
inline scalar psi(const scalar rho, const scalar T) const;
//- Return compression factor []
inline scalar Z
(
const scalar p,
const scalar T,
const scalar rho0
) const;
// I-O
//- Write to Ostream
//void write(Ostream& os) const;
// Member operators
inline void operator+=(const aungierRedlichKwong&);
inline void operator*=(const scalar);
// Friend operators
inline friend aungierRedlichKwong operator+
(
const aungierRedlichKwong&,
const aungierRedlichKwong&
);
inline friend aungierRedlichKwong operator*
(
const scalar s,
const aungierRedlichKwong&
);
// Ostream Operator
friend Ostream& operator<<(Ostream&, const aungierRedlichKwong&);
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#include "aungierRedlichKwongI.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View file

@ -0,0 +1,574 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright held by original author
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM; if not, write to the Free Software Foundation,
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Author
Christian Lucas
Institut für Thermodynamik
Technische Universität Braunschweig
Germany
\*---------------------------------------------------------------------------*/
#include "aungierRedlichKwong.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
// Construct from components
inline aungierRedlichKwong::aungierRedlichKwong
(
const specie& sp
)
:
specie(sp),
TSave(0)
{}
// Construct as named copy
inline aungierRedlichKwong::aungierRedlichKwong(const word& name, const aungierRedlichKwong& pg)
:
specie(name, pg),
pcrit_(pg.pcrit_),
Tcrit_(pg.Tcrit_),
rhocrit_(pg.rhocrit_),
azentricFactor_(pg.azentricFactor_),
a0_(pg.a0_),
b_(pg.b_),
c_(pg.c_),
n_(pg.n_),
b2_(pg.b2_),
b3_(pg.b3_),
b4_(pg.b4_),
b5_(pg.b5_),
c2_(pg.c2_),
rhoMin_(pg.rhoMin_),
rhoMax_(pg.rhoMax_),
rhostd_(pg.rhostd_),
aSave(0.0),
daSave(0.0),
d2aSave(0.0),
TSave(0.0)
{}
// Construct and return a clone
inline autoPtr<aungierRedlichKwong> aungierRedlichKwong::clone() const
{
return autoPtr<aungierRedlichKwong>(new aungierRedlichKwong(*this));
}
// Selector from Istream
inline autoPtr<aungierRedlichKwong> aungierRedlichKwong::New(Istream& is)
{
return autoPtr<aungierRedlichKwong>(new aungierRedlichKwong(is));
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
inline scalar aungierRedlichKwong::rhostd() const
{
return rhostd_;
}
inline scalar aungierRedlichKwong::rhoMin() const
{
return rhoMin_;
}
inline scalar aungierRedlichKwong::rhoMax() const
{
return rhoMax_;
}
inline scalar aungierRedlichKwong::Tcrit() const
{
return Tcrit_;
}
inline scalar aungierRedlichKwong::pcrit() const
{
return pcrit_;
}
inline scalar aungierRedlichKwong::rhocrit() const
{
return rhocrit_;
}
inline scalar aungierRedlichKwong::azentricFactor() const
{
return azentricFactor_;
}
inline void aungierRedlichKwong::updateModelCoefficients(const scalar T)const
{
aSave=a0_*pow(T/Tcrit_, -n_);
daSave=-a0_*n_*pow(T/Tcrit_, -n_)/T;
d2aSave=a0_*(n_*n_ + n_)/(T*T)*pow(T/Tcrit_, -n_);
//CL: saving the temperature at which the coefficients are valid
TSave=T;
}
//CL: Model coefficient a(T)
inline scalar aungierRedlichKwong::a(const scalar T)const
{
//CL: check if a has already been calculated for this temperature
if(TSave==T)
{
return aSave;
}
//CL: If not, recalculate a(T), dadT(T) and d2adT2(T)
else
{
updateModelCoefficients(T);
return aSave;
}
}
//CL: temperature deriviative of model coefficient a(T)
inline scalar aungierRedlichKwong::dadT(const scalar T)const
{
// check if a has already been calculated for this temperature
if(TSave==T)
{
return daSave;
}
//CL: If not, recalculate a(T), dadT(T) and d2adT2(T)
else
{
updateModelCoefficients(T);
return daSave;
}
}
//CL: second order temperature deriviative of model coefficient a(T)
inline scalar aungierRedlichKwong::d2adT2(const scalar T)const
{
// check if a has already been calculated for this temperature
if(TSave==T)
{
return d2aSave;
}
//CL: If not, recalculate a(T), dadT(T) and d2adT2(T)
else
{
updateModelCoefficients(T);
return d2aSave;
}
}
//Aungier Redlich Kwong factors
inline scalar aungierRedlichKwong::a0() const
{
return a0_;
}
inline scalar aungierRedlichKwong::b() const
{
return b_;
}
inline scalar aungierRedlichKwong::c() const
{
return c_;
}
inline scalar aungierRedlichKwong::n() const
{
return n_;
}
//returns the pressure for a given density and temperature
inline scalar aungierRedlichKwong::p(const scalar rho, const scalar T) const
{
scalar Vm = this->W()/rho;
return this->RR()*T/(Vm - b_ + c_) - a(T)/(Vm*(Vm + b_));
}
//Real deviative dp/dv at constant temperature
//(molar values)
inline scalar aungierRedlichKwong::dpdv(const scalar rho, const scalar T) const
{
scalar Vm = this->W()/rho;
scalar Vm2 = Vm*Vm;
return
(
a(T)*(b3_ - 2*b2_*c_ + b_*(c_ + Vm)*(c_ - 3*Vm) + 2*Vm*pow(c_ + Vm, 2))
- this->RR()*T*Vm2*(b2_ + 2*b_*Vm + Vm2)
)
/(Vm2*pow(b_ - c_ - Vm, 2)*pow(b_ + Vm, 2));
}
//Real deviative dp/dT at constant molar volume
//(molar values)
inline scalar aungierRedlichKwong::dpdT(const scalar rho, const scalar T) const
{
scalar Vm = this->W()/rho;
return this->RR()/(Vm - b_ + c_)-dadT(T)/(Vm*(Vm + b_));
}
//Real deviative dv/dT at constant pressure
//using implicit differentiation
//(molar values)
inline scalar aungierRedlichKwong::dvdT(const scalar rho, const scalar T) const
{
return -this->dpdT(rho, T)/this->dpdv(rho, T);
}
//Real deviative dv/dp at constant temperature
//(molar values)
inline scalar aungierRedlichKwong::dvdp(const scalar rho, const scalar T) const
{
return 1/this->dpdv(rho, T);
}
//needed to calculate the internal energy
//(molar values)
inline scalar aungierRedlichKwong::integral_p_dv
(
const scalar rho,
const scalar T
) const
{
scalar Vm = this->W()/rho;
return this->RR()*T*log(-b_ + c_ + Vm) + a(T)/b_*(log(b_ + Vm) - log(Vm));
//return this->RR()*T*log(-b_ + c_ + Vm) + a(T)*log(b_ + Vm)/b_ - a(T)*log(Vm)/b_;
}
//needed to calculate the entropy
//(molar values)
inline scalar aungierRedlichKwong::integral_dpdT_dv
(
const scalar rho,
const scalar T
) const
{
scalar Vm = this->W()/rho;
return this->RR()*log(-b_ + c_ + Vm) + dadT(T)/b_*(log(b_ + Vm) - log(Vm));
//return this->RR()*log(-b_ + c_ + Vm) + dadT(T)*log(b_ + Vm)/b_ - dadT(T)*log(Vm)/b_;
}
//(molar values)
inline scalar aungierRedlichKwong::d2pdT2(const scalar rho,const scalar T) const
{
scalar Vm = this->W()/rho;
return -d2adT2(T)/(Vm*(Vm + b_));
}
//(molar values)
inline scalar aungierRedlichKwong::d2pdv2(const scalar rho,const scalar T) const
{
scalar Vm = this->W()/rho;
scalar Vm2 = Vm*Vm;
scalar Vm3 = Vm2*Vm;
return -2*
(
a(T)*
(
b5_ - 3*b4_*c_ + 3*b3_*(c2_ - c_*Vm - Vm2)
- b2_*(c_ + Vm)*(c2_ - 7*c_*Vm+Vm2)
+ 3*b_*Vm*pow(c_ + Vm, 2)*(2*Vm - c_)
- 3*Vm2*pow(c_ + Vm, 3)
)
+ this->RR()*T*Vm3*(b3_ + 3*b2_*Vm + 3*b_*Vm2 + Vm3)
)
/(Vm3*pow(b_ - c_ - Vm, 3)*pow(b_ + Vm, 3));
}
//(molar values)
//using second order implicit differentiation
inline scalar aungierRedlichKwong::d2vdT2
(
const scalar rho,
const scalar T
) const
{
scalar dpdT2=this->dpdT(rho, T)*this->dpdT(rho, T);
scalar dpdv2=this->dpdv(rho, T)*this->dpdv(rho, T);
scalar dpdv3=dpdv2*this->dpdv(rho, T);
return
-(
dpdT2*this->d2pdv2(rho, T)
+ dpdv2*this->d2pdT2(rho, T)
- 2*this->dpdv(rho, T)*this->dpdT(rho, T)*this->d2pdvdT(rho, T)
)
/dpdv3;
}
//(molar values)
inline scalar aungierRedlichKwong::d2pdvdT
(
const scalar rho,
const scalar T
) const
{
scalar Vm = this->W()/rho;
scalar Vm2 = Vm*Vm;
return
(
dadT(T)*(b3_ - 2*b2_*c_ + b_*(c_ + Vm)*(c_ - 3*Vm)+2*Vm*pow(c_ + Vm, 2))
- this->RR()*Vm2*(b2_ + 2*b_*Vm + Vm2)
)
/(Vm2*pow(b_ - c_ - Vm, 2)*pow(b_ + Vm, 2));
}
// the result of this intergal is needed for the nasa based cp polynomial
//(molar values)
inline scalar aungierRedlichKwong::integral_d2pdT2_dv
(
const scalar rho,
const scalar T
) const
{
scalar Vm = this->W()/rho;
return d2adT2(T)*log(b_ + Vm)/b_ - d2adT2(T)*log(Vm)/b_;
}
//Isobar expansion Coefficent beta = 1/v (dv/dt) at constant p
//(molar values)
inline scalar aungierRedlichKwong::isobarExpCoef
(
const scalar rho,
const scalar T
) const
{
return this->dvdT(rho, T)*rho/this->W();
}
//isothemal compressiblity kappa (not Thermal conductivity)
//(molar values)
inline scalar aungierRedlichKwong::isothermalCompressiblity
(
const scalar rho,
const scalar T
) const
{
return this->isobarExpCoef(rho, T)/this->dpdT(rho, T);
//also possible : return -this->dvdp(rho,T)*rho/this->W();
}
//- Return density [kg/m^3]
inline scalar aungierRedlichKwong::rho
(
const scalar p,
const scalar T,
const scalar rho0
) const
{
scalar molarVolumePrevIteration;
scalar molarVolume;
label iter = 0;
label maxIter_ = 400;
scalar tol_ = 1e-8;
scalar rho1 = rhoMax_;
scalar rho2 = rhoMin_;
molarVolume = this->W()/rho0;
do
{
molarVolumePrevIteration= molarVolume;
label i=0;
do
{
//CL: modified Newton solver
molarVolume=molarVolumePrevIteration
-(
(this->p((this->W()/molarVolumePrevIteration),T) - p)
/(this->dpdv((this->W()/molarVolumePrevIteration), T))
)/pow(2,i);
i++;
if (i>8)
{
//CL: using bisection methode as backup,
//CL: solution must be between rhoMin_ to rhoMax
for(i=0; i<200; i++)
{
scalar f1 = this->p(rho1, T) - p;
scalar f2 = this->p(rho2, T) - p;
scalar rho3 = (rho1 + rho2)/2;
scalar f3 = this->p(rho3, T) - p;
if ((f2 < 0 && f3 > 0) || (f2 > 0 && f3 < 0))
{
rho1=rho3;
}
else if ((f1 < 0 && f3 > 0)||(f1 > 0 && f3 < 0))
{
rho2=rho3;
}
else
{
rho2=(rho2 + rho3)/2;
}
if(mag(f3) < p*tol_)
{
molarVolume=this->W()/rho3;
molarVolumePrevIteration=this->W()/rho3;
break;
}
else
{
molarVolumePrevIteration=this->W()/rho3;
}
}
}
}
while
(
mag(this->p((this->W()/molarVolume), T) - p)
> mag(this->p((this->W()/molarVolumePrevIteration), T) - p)
);
if (iter++ > maxIter_)
{
FatalErrorIn
(
"inline scalar aungierRedlichKwong::rho"
"(const scalar p, const scalar T, const scalar rho0) const "
) << "Maximum number of iterations exceeded"
<< abort(FatalError);
}
}
while(mag(molarVolumePrevIteration-molarVolume) > tol_*(this->W()/rho0));
return this->W()/molarVolume;
}
//- Return density [kg/m^3]
inline scalar aungierRedlichKwong::rho(const scalar p, const scalar T) const
{
//CL: using perfect gas equation as starting point
return rho(p, T, p/(this->R()*T));
}
//- Return compressibility drho/dp at T=constant [s^2/m^2]
inline scalar aungierRedlichKwong::psi(const scalar rho, const scalar T) const
{
return -this->dvdp(rho, T)*rho*rho/this->W();
}
//- Return compression factor []
inline scalar aungierRedlichKwong::Z
(
const scalar p,
const scalar T,
const scalar rho0
) const
{
return p/(this->R()*T*this->rho(p, T, rho0));
}
// * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * //
inline void aungierRedlichKwong::operator+=(const aungierRedlichKwong& ark)
{
specie::operator+=(ark);
}
inline void aungierRedlichKwong::operator*=(const scalar s)
{
specie::operator*=(s);
}
// * * * * * * * * * * * * * * * Friend Operators * * * * * * * * * * * * * //
inline aungierRedlichKwong operator+
(
const aungierRedlichKwong& ark1,
const aungierRedlichKwong& ark2
)
{
return aungierRedlichKwong
(
static_cast<const specie&>(ark1)
+ static_cast<const specie&>(ark2)
);
}
inline aungierRedlichKwong operator*
(
const scalar s,
const aungierRedlichKwong& ark
)
{
return aungierRedlichKwong(s*static_cast<const specie&>(ark));
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// ************************************************************************* //

View file

@ -0,0 +1,128 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | foam-extend: Open Source CFD
\\ / O peration |
\\ / A nd | For copyright notice see file Copyright
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of foam-extend.
foam-extend is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation, either version 3 of the License, or (at your
option) any later version.
foam-extend is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with foam-extend. If not, see <http://www.gnu.org/licenses/>.
Description
Peng Robinson equation of state.
Author
Christian Lucas
Institut für Thermodynamik
Technische Universität Braunschweig
Germany
\*---------------------------------------------------------------------------*/
#include "pengRobinson.H"
#include "IOstreams.H"
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::pengRobinson::pengRobinson(Istream& is)
:
specie(is),
pcrit_(readScalar(is)),
Tcrit_(readScalar(is)),
azentricFactor_(readScalar(is)),
a0_(0.457235*pow(this->RR(), 2)*pow(Tcrit_, 2)/pcrit_),
b_(0.077796*this->RR()*Tcrit_/pcrit_),
n_(0.37464 + 1.54226*azentricFactor_ - 0.26992*pow(azentricFactor_, 2)),
b2_(b_*b_),
b3_(b2_*b_),
b4_(b3_*b_),
b5_(b4_*b_),
b6_(b5_*b_),
//CL: Only uses the default values
rhoMin_(1e-3),
rhoMax_(1500),
// Starting GUESS for the density by ideal gas law
rhostd_(this->rho(this->Pstd(), this->Tstd(), this->Pstd()/(this->Tstd()*this->R()))),
aSave(0.0),
daSave(0.0),
d2aSave(0.0),
TSave(0.0)
{
is.check("pengRobinson::pengRobinson(Istream& is)");
}
//CL: Constructed needed in OpenFOAM 2.x.x
//CL: Code works fine, but compiling problem in OpenFOAM 1.6.ext
//CL: because specie has no constructor using dict
/*
pengRobinson::pengRobinson(const dictionary& dict)
:
specie(dict),
pcrit_(readScalar(dict.subDict("equationOfState").lookup("pCritical"))),
Tcrit_(readScalar(dict.subDict("equationOfState").lookup("TCritical"))),
azentricFactor_(readScalar(dict.subDict("equationOfState").lookup("azentricFactor"))),
//CL: rhoMin and rhoMax are only used as boundaries for the bisection methode (see rho function)
//CL: important: rhoMin and rhoMax are not used as boundary for the newton solver
//CL: therefore, rho can be larger than rhoMax and smaller than rhoMin
a0_(0.457235*pow(this->RR(), 2)*pow(Tcrit_, 2)/pcrit_),
b_(0.077796*this->RR()*Tcrit_/pcrit_),
n_(0.37464 + 1.54226*azentricFactor_ - 0.26992*pow(azentricFactor_, 2)),
b2_(b_*b_),
b3_(b2_*b_),
b4_(b3_*b_),
b5_(b4_*b_),
b6_(b5_*b_),
rhoMin_(dict.subDict("equationOfState").lookupOrDefault("rhoMin",1e-3)),
rhoMax_(dict.subDict("equationOfState").lookupOrDefault("rhoMax",1500)),
aSave(0.0),
daSave(0.0),
d2aSave(0.0),
TSave(0.0),
// Starting GUESS for the density by ideal gas law
rhostd_(this->rho(this->Pstd(), this->Tstd(), this->Pstd()/(this->Tstd()*this->R())))
{}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
void Foam::pengRobinson::write(Ostream& os) const
{
specie::write(os);
dictionary dict("equationOfState");
dict.add("pCritical", pcrit_);
dict.add("TCritical", Tcrit_);
dict.add("azentricFactor", azentricFactor_);
dict.add("rhoMin", rhoMin_);
dict.add("rhoMax", rhoMax_);
os << indent << dict.dictName() << dict;
}
*/
// * * * * * * * * * * * * * * * Ostream Operator * * * * * * * * * * * * * //
Foam::Ostream& Foam::operator<<(Ostream& os, const pengRobinson& pr)
{
os << static_cast<const specie&>(pr)<< token::SPACE
<< pr.pcrit_ << tab<< pr.Tcrit_<< tab << pr.azentricFactor_;
os.check("Ostream& operator<<(Ostream& os, const pengRobinson& st)");
return os;
}
// ************************************************************************* //

View file

@ -0,0 +1,281 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | foam-extend: Open Source CFD
\\ / O peration |
\\ / A nd | For copyright notice see file Copyright
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of foam-extend.
foam-extend is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation, either version 3 of the License, or (at your
option) any later version.
foam-extend is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with foam-extend. If not, see <http://www.gnu.org/licenses/>.
Class
Foam::pengRobinson
Description
Peng Robinson equation of state.
Paper:
Title: A New Two-Constant Equation of State
Authors: Ding-Yu Peng and Donald B. Robinson
Journal: Ind. Eng. Chem., Fundam., Vol. 15, No. 1, 1976
SourceFiles
pengRobinsonI.H
pengRobinson.C
Author
Christian Lucas
Institut für Thermodynamik
Technische Universität Braunschweig
Germany
\*---------------------------------------------------------------------------*/
#ifndef pengRobinson_H
#define pengRobinson_H
#include "specie.H"
#include "autoPtr.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
/*---------------------------------------------------------------------------*\
Class Peng Robinson Declaration
\*---------------------------------------------------------------------------*/
class pengRobinson
:
public specie
{
// private data
//CL: data at critical point
scalar pcrit_;
scalar Tcrit_;
scalar azentricFactor_;
//-Peng Robinson factors
scalar a0_;
scalar b_;
scalar n_;
//CL: pow of constants b_ used in the code e.g. b2_=b*b;
scalar b2_;
scalar b3_;
scalar b4_;
scalar b5_;
scalar b6_;
//CL: rhoMin and rhoMax are only used as boundaries for the bisection methode (see rho function)
scalar rhoMin_;
scalar rhoMax_;
//- Density @STD, initialise after a0, b!
scalar rhostd_;
//CL: Variables to save the values of a, dadT and d2adT2 of the mixture
//CL: Variables must corrected for changing temperatures
mutable scalar aSave;
mutable scalar daSave;
mutable scalar d2aSave;
//CL: save the temperature for which the save coefficients (amix,dadTmix,d2adT2mix) are correct
mutable scalar TSave;
//Protected functions
//CL: function updates the coefficients (aSave, daSave, d2aSave)
inline void updateModelCoefficients(const scalar T) const;
public:
// Constructors
//- Construct from components
inline pengRobinson
(
const specie& sp
);
//- Construct from Istream
pengRobinson(Istream&);
//- Construct from dictionary
//pengRobinson(const dictionary& dict);
//- Construct as named copy
inline pengRobinson(const word& name,const pengRobinson&);
//- Construct and return a clone
inline autoPtr<pengRobinson> clone() const;
// Selector from Istream
inline static autoPtr<pengRobinson> New(Istream& is);
// Member functions
//Return Peng Robinson factors
inline scalar a0() const;
inline scalar b() const;
inline scalar n() const;
inline scalar rhostd() const;
inline scalar rhoMin() const;
inline scalar rhoMax() const;
inline scalar Tcrit() const;
//CL: Model coefficient a(T)
inline scalar a(const scalar T) const;
//CL: temperature deriviative of model coefficient a(T)
inline scalar dadT(const scalar T) const;
//CL: second order temperature deriviative of model coefficient a(T)
inline scalar d2adT2(const scalar T) const;
//CL: Equation of state
inline scalar p(const scalar rho, const scalar T) const;
//CL: first order derivatives
inline scalar dpdv(const scalar rho, const scalar T) const;
inline scalar dpdT(const scalar rho, const scalar T) const;
inline scalar dvdT(const scalar rho, const scalar T) const;
inline scalar dvdp(const scalar rho, const scalar T) const;
inline scalar isobarExpCoef
(
const scalar rho,
const scalar T
) const;
inline scalar isothermalCompressiblity
(
const scalar rho,
const scalar T
) const;
//CL: Used for cv
inline scalar integral_d2pdT2_dv
(
const scalar rho,
const scalar T
) const;
//CL: second order derivatives, not Used At The Moment
inline scalar d2pdv2(const scalar rho, const scalar T) const;
inline scalar d2pdT2(const scalar rho, const scalar T) const;
inline scalar d2pdvdT(const scalar rho, const scalar T) const;
inline scalar d2vdT2(const scalar rho, const scalar T) const;
//CL: Used for internal Energy
inline scalar integral_p_dv
(
const scalar rho,
const scalar T
) const;
//CL: Used for Entropy
inline scalar integral_dpdT_dv
(
const scalar rho,
const scalar T
) const;
//- Return density [kg/m^3]
// rho0 is the starting point of the newton solver used to calculate rho
inline scalar rho
(
const scalar p,
const scalar T,
const scalar rho0
) const;
inline scalar rho(const scalar p, const scalar T) const;
//- Return compressibility drho/dp at T=constant [s^2/m^2]
inline scalar psi(const scalar rho, const scalar T) const;
//- Return compression factor []
inline scalar Z
(
const scalar p,
const scalar T,
const scalar rho0
) const;
// I-O
//- Write to Ostream
//void write(Ostream& os) const;
// Member operators
inline void operator+=(const pengRobinson&);
inline void operator*=(const scalar);
// Friend operators
inline friend pengRobinson operator+
(
const pengRobinson&,
const pengRobinson&
);
inline friend pengRobinson operator*
(
const scalar s,
const pengRobinson&
);
// Ostream Operator
friend Ostream& operator<<(Ostream&, const pengRobinson&);
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#include "pengRobinsonI.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View file

@ -0,0 +1,578 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright held by original author
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM; if not, write to the Free Software Foundation,
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Author
Christian Lucas
Institut für Thermodynamik
Technische Universität Braunschweig
Germany
\*---------------------------------------------------------------------------*/
#include "pengRobinson.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
// Construct from components
inline pengRobinson::pengRobinson
(
const specie& sp
)
:
specie(sp),
TSave(0)
{}
// Construct as named copy
inline pengRobinson::pengRobinson(const word& name, const pengRobinson& pr)
:
specie(name, pr),
pcrit_(pr.pcrit_),
Tcrit_(pr.Tcrit_),
azentricFactor_(pr.azentricFactor_),
a0_(pr.a0_),
b_(pr.b_),
n_(pr.n_),
b2_(pr.b2_),
b3_(pr.b3_),
b4_(pr.b4_),
b5_(pr.b5_),
b6_(pr.b6_),
rhoMin_(pr.rhoMin_),
rhoMax_(pr.rhoMax_),
rhostd_(pr.rhostd_),
aSave(0.0),
daSave(0.0),
d2aSave(0.0),
TSave(0.0)
{}
// Construct and return a clone
inline autoPtr<pengRobinson> pengRobinson::clone() const
{
return autoPtr<pengRobinson>(new pengRobinson(*this));
}
// Selector from Istream
inline autoPtr<pengRobinson> pengRobinson::New(Istream& is)
{
return autoPtr<pengRobinson>(new pengRobinson(is));
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
inline scalar pengRobinson::rhostd() const
{
return rhostd_;
}
inline scalar pengRobinson::rhoMin() const
{
return rhoMin_;
}
inline scalar pengRobinson::rhoMax() const
{
return rhoMax_;
}
inline scalar pengRobinson::Tcrit() const
{
return Tcrit_;
}
inline void pengRobinson::updateModelCoefficients(const scalar T) const
{
aSave=a0_*pow(1 + n_*(1 - pow(T/Tcrit_, 0.5)), 2);
daSave=a0_*n_*(n_*sqrt(T/Tcrit_) - n_ - 1)*sqrt(T/Tcrit_)/T;
d2aSave=a0_*n_*(n_ + 1)*sqrt(T/Tcrit_)/(2*T*T);
//CL: saving the temperature at which the coefficients are valid
TSave=T;
}
//CL: Model coefficient a(T)
inline scalar pengRobinson::a(const scalar T) const
{
//CL: check if a has already been calculated for this temperature
if(TSave==T)
{
return aSave;
}
//CL: If not, recalculate a(T), dadT(T) and d2adT2(T)
else
{
updateModelCoefficients(T);
return aSave;
}
}
//CL: temperature deriviative of model coefficient a(T)
inline scalar pengRobinson::dadT(const scalar T) const
{
// check if a has already been calculated for this temperature
if(TSave==T)
{
return daSave;
}
//CL: If not, recalculate a(T), dadT(T) and d2adT2(T)
else
{
updateModelCoefficients(T);
return daSave;
}
}
//CL: second order temperature deriviative of model coefficient a(T)
inline scalar pengRobinson::d2adT2(const scalar T) const
{
// check if a has already been calculated for this temperature
if(TSave==T)
{
return d2aSave;
}
//CL: If not, recalculate a(T), dadT(T) and d2adT2(T)
else
{
updateModelCoefficients(T);
return d2aSave;
}
}
inline scalar pengRobinson::a0() const
{
return a0_;
}
inline scalar pengRobinson::b() const
{
return b_;
}
inline scalar pengRobinson::n() const
{
return n_;
}
//returns the pressure for a given density and temperature
inline scalar pengRobinson::p(const scalar rho, const scalar T) const
{
scalar Vm = this->W()/rho;
scalar Vm2 = Vm*Vm;
return this->RR()*T/(Vm - b_) - a(T)/(Vm2 + 2*b_*Vm - b2_);
}
//Real deviative dp/dv at constant temperature
//(molar values)
inline scalar pengRobinson::dpdv(const scalar rho, const scalar T) const
{
scalar Vm = this->W()/rho;
scalar Vm2 = Vm*Vm;
scalar Vm3 = Vm2*Vm;
scalar Vm4 = Vm3*Vm;
return
(
2*a(T)*
(
b3_ - b2_*Vm - b_*Vm2 + Vm3
)
- this->RR()*T*
(
b4_ - 4*b3_*Vm + 2*b2_*Vm2 + 4*b_*Vm3 + Vm4
)
)
/(pow(b_ - Vm, 2)*pow(b2_ - 2*b_*Vm - Vm2, 2));
}
//Real deviative dp/dT at constant molar volume
//(molar values)
inline scalar pengRobinson::dpdT(const scalar rho, const scalar T) const
{
scalar Vm = this->W()/rho;
scalar Vm2 = Vm*Vm;
return this->RR()/(Vm - b_) - dadT(T)/(Vm2 + 2*b_*Vm - b2_);
}
//Real deviative dv/dT at constant pressure
//by using implicit differentiation
//(molar values)
inline scalar pengRobinson::dvdT(const scalar rho, const scalar T) const
{
return -this->dpdT(rho, T)/this->dpdv(rho, T);
}
//Real deviative dv/dp at constant temperature
//(molar values)
inline scalar pengRobinson::dvdp(const scalar rho, const scalar T) const
{
return 1/this->dpdv(rho, T);
}
//needed to calculate the internal energy
//(molar values)
inline scalar pengRobinson::integral_p_dv
(
const scalar rho,
const scalar T
) const
{
scalar Vm = this->W()/rho;
scalar root2=pow(2, 0.5);
return
- root2*a(T)*log(b_*(1-root2) + Vm)/(4*b_)
+ this->RR()*T*log(Vm - b_)
+ root2*a(T)*log(b_*(root2 + 1) + Vm)/(4*b_);
}
//needed to calculate the entropy
//(molar values)
//needed to calculate the entropy
inline scalar pengRobinson::integral_dpdT_dv
(
const scalar rho,
const scalar T
) const
{
scalar Vm = this->W()/rho;
scalar root2=pow(2, 0.5);
return
- root2*dadT(T)*log(b_*(1 - root2) + Vm)/(4*b_)
+ this->RR()*log(Vm - b_) + root2*dadT(T)*log(b_*(root2 + 1) + Vm)/(4*b_);
}
//(molar values)
inline scalar pengRobinson::d2pdT2(const scalar rho, const scalar T) const
{
scalar Vm = this->W()/rho;
scalar Vm2 = Vm*Vm;
return -d2adT2(T)/(Vm2 + 2*b_*Vm-b2_);
}
//(molar values)
inline scalar pengRobinson::d2pdv2(const scalar rho, const scalar T) const
{
scalar Vm = this->W()/rho;
scalar Vm2 = Vm*Vm;
scalar Vm3 = Vm2*Vm;
scalar Vm4 = Vm3*Vm;
scalar Vm5 = Vm4*Vm;
scalar Vm6 = Vm5*Vm;
return 2*
(
a(T)*
(
5*b5_ - 9*b4_*Vm + 4*b2_*Vm3 + 3*b_*Vm4 - 3*Vm5
)
- this->RR()*T*
(
b6_ - 6*b5_*Vm + 9*b4_*Vm2 + 4*b3_*Vm3 - 9*b2_*Vm4 - 6*b_*Vm5 - Vm6
)
)
/(pow(b_ - Vm, 3)*pow(b2_ - 2*b_*Vm - Vm2, 3));
}
//(molar values)
//using second order implicit differentiation
inline scalar pengRobinson::d2vdT2
(
const scalar rho,
const scalar T
) const
{
scalar dpdT2=this->dpdT(rho, T)*this->dpdT(rho, T);
scalar dpdv2=this->dpdv(rho, T)*this->dpdv(rho, T);
scalar dpdv3=dpdv2*this->dpdv(rho, T);
return
-(
dpdT2*this->d2pdv2(rho, T)
+ dpdv2*this->d2pdT2(rho, T)
- 2*this->dpdv(rho, T)*this->dpdT(rho, T)*this->d2pdvdT(rho, T)
)
/dpdv3;
}
//(molar values)
inline scalar pengRobinson::d2pdvdT
(
const scalar rho,
const scalar T
) const
{
scalar Vm = this->W()/rho;
scalar Vm2 = Vm*Vm;
scalar Vm3 = Vm2*Vm;
scalar Vm4 = Vm3*Vm;
return
(
2*dadT(T)*(b3_ - b2_*Vm - b_*Vm2 + Vm3)
- this->RR()*(b4_ - 4*b3_*Vm + 2*b2_*Vm2 + 4*b_*Vm3 + Vm4)
)
/(pow(b_ - Vm, 2)*pow(b2_ - 2*b_*Vm - Vm2, 2));
}
// the result of this intergal is needed for the nasa based cp polynomial
//(molar values)
inline scalar pengRobinson::integral_d2pdT2_dv
(
const scalar rho,
const scalar T
) const
{
scalar Vm = this->W()/rho;
scalar root2=pow(2, 0.5);
return root2*d2adT2(T)/(4*b_)
*(log(b_*(root2 + 1) + Vm) - log(b_*(1 - root2) + Vm));
// root2*d2adT2(T)*log(b_*(root2 + 1) + Vm)/(4*b_)
//- root2*d2adT2(T)*log(b_*(1 - root2)+Vm)/(4*b_);
}
//Isobar expansion Coefficent beta = 1/v (dv/dt) at constant p
//(molar values)
inline scalar pengRobinson::isobarExpCoef
(
const scalar rho,
const scalar T
) const
{
return this->dvdT(rho, T)*rho/this->W();
}
//isothemal compressiblity kappa (not Thermal conductivity)
//(molar values)
inline scalar pengRobinson::isothermalCompressiblity
(
const scalar rho,
const scalar T
) const
{
return this->isobarExpCoef(rho, T)/this->dpdT(rho, T);
//CL: also possible
//CL: return -this->dvdp(rho, T)*rho/this->W();
}
//- Return density [kg/m^3]
inline scalar pengRobinson::rho
(
const scalar p,
const scalar T,
const scalar rho0
) const
{
scalar molarVolumePrevIteration;
scalar molarVolume;
label iter = 0;
label maxIter_ = 400;
scalar tol_ = 1e-8;
scalar rho1 = rhoMax_;
scalar rho2 = rhoMin_;
molarVolume = this->W()/rho0;
do
{
molarVolumePrevIteration= molarVolume;
label i=0;
do
{
//CL: modified Newton solver
molarVolume=molarVolumePrevIteration
-(
(this->p((this->W()/molarVolumePrevIteration),T) - p)
/(this->dpdv((this->W()/molarVolumePrevIteration), T))
)/pow(2,i);
i++;
if (i>8)
{
//CL: using bisection methode as backup,
//CL: solution must be between rhoMin_ to rhoMax
for(i=0; i<200; i++)
{
scalar f1 = this->p(rho1, T) - p;
scalar f2 = this->p(rho2, T) - p;
scalar rho3 = (rho1 + rho2)/2;
scalar f3 = this->p(rho3, T) - p;
if ((f2 < 0 && f3 > 0) || (f2 > 0 && f3 < 0))
{
rho1=rho3;
}
else if ((f1 < 0 && f3 > 0)||(f1 > 0 && f3 < 0))
{
rho2=rho3;
}
else
{
rho2=(rho2 + rho3)/2;
}
if(mag(f3) < p*tol_)
{
molarVolume=this->W()/rho3;
molarVolumePrevIteration=this->W()/rho3;
break;
}
else
{
molarVolumePrevIteration=this->W()/rho3;
}
}
}
}
while
(
mag(this->p((this->W()/molarVolume), T) - p)
> mag(this->p((this->W()/molarVolumePrevIteration), T) - p)
);
if (iter++ > maxIter_)
{
FatalErrorIn
(
"inline scalar pengRobinson::rho"
"(const scalar p, const scalar T, const scalar rho0) const "
) << "Maximum number of iterations exceeded"
<< abort(FatalError);
}
}
while(mag(molarVolumePrevIteration-molarVolume) > tol_*(this->W()/rho0));
return this->W()/molarVolume;
}
//- Return density [kg/m^3]on
inline scalar pengRobinson::rho(const scalar p, const scalar T) const
{
//CL: using perfect gas equation as starting point
return rho(p, T, p/(this->R()*T));
}
//- Return compressibility drho/dp at T=constant [s^2/m^2]
inline scalar pengRobinson::psi(const scalar rho, const scalar T) const
{
return -this->dvdp(rho, T)*rho*rho/this->W();
}
//- Return compression factor []
inline scalar pengRobinson::Z
(
const scalar p,
const scalar T,
const scalar rho0
) const
{
return p/(this->R()*T*this->rho(p, T, rho0));
}
// * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * //
inline void pengRobinson::operator+=(const pengRobinson& pr)
{
specie::operator+=(pr);
}
inline void pengRobinson::operator*=(const scalar s)
{
specie::operator*=(s);
}
// * * * * * * * * * * * * * * * Friend Operators * * * * * * * * * * * * * //
inline pengRobinson operator+
(
const pengRobinson& pr1,
const pengRobinson& pr2
)
{
return pengRobinson
(
static_cast<const specie&>(pr1)
+ static_cast<const specie&>(pr2)
);
}
inline pengRobinson operator*
(
const scalar s,
const pengRobinson& pr
)
{
return pengRobinson(s*static_cast<const specie&>(pr));
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// ************************************************************************* //

View file

@ -0,0 +1,115 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright held by original author
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM; if not, write to the Free Software Foundation,
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Description
Redlich Kwong equation of state.
Author
Christian Lucas
Institut für Thermodynamik
Technische Universität Braunschweig
Germany
\*---------------------------------------------------------------------------*/
#include "redlichKwong.H"
#include "IOstreams.H"
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::redlichKwong::redlichKwong(Istream& is)
:
specie(is),
pcrit_(readScalar(is)),
Tcrit_(readScalar(is)),
a_(0.42748*pow(this->RR(), 2)*pow(Tcrit_, 2.5)/pcrit_),
b_(0.08664*this->RR()*Tcrit_/pcrit_),
b2_(pow(b_,2)),
b3_(pow(b_,3)),
b5_(pow(b_,5)),
//CL: Only uses the default values
rhoMin_(1e-3),
rhoMax_(1500),
// Starting GUESS for the density by ideal gas law
rhostd_(this->rho(this->Pstd(), this->Tstd(), this->Pstd()/(this->Tstd()*this->R())))
{
is.check("redlichKwong::redlichKwong(Istream& is)");
}
//CL: Constructed needed in OpenFOAM 2.x.x
//CL: Code works fine, but compiling problem in OpenFOAM 1.6.ext
//CL: because specie has no constructor using dict
/*
Foam::redlichKwong::redlichKwong(const dictionary& dict)
:
specie(dict),
pcrit_(readScalar(dict.subDict("equationOfState").lookup("pCritical"))),
Tcrit_(readScalar(dict.subDict("equationOfState").lookup("TCritical"))),
a_(0.42748*pow(this->RR(),2)*pow(Tcrit_,2.5)/pcrit_),
b_(0.08664*this->RR()*Tcrit_/pcrit_),
b2_(pow(b_,2)),
b3_(pow(b_,3)),
b5_(pow(b_,5)),
//CL: rhoMin and rhoMax are only used as boundaries for the bisection methode (see rho function)
//CL: important: rhoMin and rhoMax are not used as boundary for the newton solver
//CL: therefore, rho can be larger than rhoMax and smaller than rhoMin
rhoMin_(dict.subDict("equationOfState").lookupOrDefault("rhoMin",1e-3)),
rhoMax_(dict.subDict("equationOfState").lookupOrDefault("rhoMax",1500)),
// Starting GUESS for the density by ideal gas law
rhostd_(this->rho(this->Pstd(), this->Tstd(), this->Pstd()/(this->Tstd()*this->R())))
{
is.check("redlichKwong::redlichKwong(Istream& is)");
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
void Foam::redlichKwong::write(Ostream& os) const
{
specie::write(os);
dictionary dict("equationOfState");
dict.add("pCritical", pcrit_);
dict.add("TCritical", Tcrit_);
dict.add("rhoMin", rhoMin_);
dict.add("rhoMax", rhoMax_);
os << indent << dict.dictName() << dict;
}
*/
// * * * * * * * * * * * * * * * Ostream Operator * * * * * * * * * * * * * //
Foam::Ostream& Foam::operator<<(Ostream& os, const redlichKwong& rk)
{
os << static_cast<const specie&>(rk)<< token::SPACE
<< rk.pcrit_ << tab<< rk.Tcrit_;
os.check("Ostream& operator<<(Ostream& os, const redlichKwong& st)");
return os;
}
// ************************************************************************* //

View file

@ -0,0 +1,234 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright held by original author
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM; if not, write to the Free Software Foundation,
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Class
Foam::redlichKwong
Description
Redlich Kwong equation of state.
SourceFiles
redlichKwongI.H
redlichKwong.C
Author
Christian Lucas
Institut für Thermodynamik
Technische Universität Braunschweig
Germany
\*---------------------------------------------------------------------------*/
#ifndef redlichKwong_H
#define redlichKwong_H
#include "specie.H"
#include "autoPtr.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
/*---------------------------------------------------------------------------*\
Class redlichKwong Declaration
\*---------------------------------------------------------------------------*/
class redlichKwong
:
public specie
{
// private data
//CL: data at critical point
scalar pcrit_;
scalar Tcrit_;
//CL: Redlich Kwong factors
scalar a_;
scalar b_;
//CL: pow of constants b_ used in the code e.g. b2_=b*b;
scalar b2_;
scalar b3_;
scalar b5_;
//CL: rhoMin and rhoMax are only used as boundaries for the bisection methode (see rho function)
scalar rhoMin_;
scalar rhoMax_;
//- Density @STD, initialise after a, b!
scalar rhostd_;
public:
// Constructors
//- Construct from components
inline redlichKwong
(
const specie& sp
);
//- Construct from Istream
redlichKwong(Istream&);
//- Construct from dictionary
//redlichKwong(const dictionary& dict);
//- Construct as named copy
inline redlichKwong(const word& name, const redlichKwong&);
//- Construct and return a clone
inline autoPtr<redlichKwong> clone() const;
// Selector from Istream
inline static autoPtr<redlichKwong> New(Istream& is);
// Member functions
//Return Redlich Kwong factors
inline scalar a() const;
inline scalar b() const;
inline scalar rhostd() const;
inline scalar rhoMin() const;
inline scalar rhoMax() const;
inline scalar Tcrit() const;
//CL: Equation of state
inline scalar p(const scalar rho, const scalar T) const;
//CL: first order derivatives
inline scalar dpdv(const scalar rho, const scalar T) const;
inline scalar dpdT(const scalar rho, const scalar T) const;
inline scalar dvdT(const scalar rho, const scalar T) const;
inline scalar dvdp(const scalar rho, const scalar T) const;
inline scalar isobarExpCoef(const scalar rho, const scalar T) const;
inline scalar isothermalCompressiblity
(
const scalar rho,
const scalar T
) const;
//CL: Used for cv
inline scalar integral_d2pdT2_dv
(
const scalar rho,
const scalar T
) const;
//Used for internal Energy
inline scalar integral_p_dv(const scalar rho, const scalar T) const;
// Used for Entropy
inline scalar integral_dpdT_dv(const scalar rho, const scalar T) const;
//CL: second order derivatives, not Used At The Moment
inline scalar d2pdv2(const scalar rho, const scalar T) const;
inline scalar d2pdT2(const scalar rho, const scalar T) const;
inline scalar d2pdvdT(const scalar rho, const scalar T) const;
inline scalar d2vdT2(const scalar rho, const scalar T) const;
//- Return density [kg/m^3]
// rho0 is the starting point of the newton solver used to calculate rho
inline scalar rho
(
const scalar p,
const scalar T,
const scalar rho0
) const;
inline scalar rho(const scalar p, const scalar T) const;
//- Return compressibility drho/dp at T=constant [s^2/m^2]
inline scalar psi(const scalar rho, const scalar T) const;
//- Return compression factor []
inline scalar Z
(
const scalar p,
const scalar T,
const scalar rho0
) const;
// I-O
//- Write to Ostream
//void write(Ostream& os) const;
// Member operators
inline void operator+=(const redlichKwong&);
inline void operator*=(const scalar);
// Friend operators
inline friend redlichKwong operator+
(
const redlichKwong&,
const redlichKwong&
);
inline friend redlichKwong operator*
(
const scalar s,
const redlichKwong&
);
// Ostream Operator
friend Ostream& operator<<(Ostream&, const redlichKwong&);
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#include "redlichKwongI.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View file

@ -0,0 +1,468 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright held by original author
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM; if not, write to the Free Software Foundation,
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Author
Christian Lucas
Institut für Thermodynamik
Technische Universität Braunschweig
Germany
\*---------------------------------------------------------------------------*/
#include "redlichKwong.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
// Construct from components
inline redlichKwong::redlichKwong
(
const specie& sp
)
:
specie(sp)
{}
// Construct as named copy
inline redlichKwong::redlichKwong(const word& name, const redlichKwong& rk)
:
specie(name, rk),
pcrit_(rk.pcrit_),
Tcrit_(rk.Tcrit_),
a_(rk.a_),
b_(rk.b_),
b2_(rk.b2_),
b3_(rk.b3_),
b5_(rk.b5_),
rhoMin_(rk.rhoMin_),
rhoMax_(rk.rhoMax_),
rhostd_(rk.rhostd_)
{}
// Construct and return a clone
inline autoPtr<redlichKwong> redlichKwong::clone() const
{
return autoPtr<redlichKwong>(new redlichKwong(*this));
}
// Selector from Istream
inline autoPtr<redlichKwong> redlichKwong::New(Istream& is)
{
return autoPtr<redlichKwong>(new redlichKwong(is));
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
inline scalar redlichKwong::rhostd() const
{
return rhostd_;
}
inline scalar redlichKwong::rhoMin() const
{
return rhoMin_;
}
inline scalar redlichKwong::rhoMax() const
{
return rhoMax_;
}
inline scalar redlichKwong::Tcrit() const
{
return Tcrit_;
}
inline scalar redlichKwong::a() const
{
return a_;
}
inline scalar redlichKwong::b() const
{
return b_;
}
//returns the pressure for a given density and temperature
inline scalar redlichKwong::p(const scalar rho, const scalar T) const
{
scalar Vm = this->W()/rho;
return this->RR()*T/(Vm - b_) - a_/(sqrt(T)*Vm*(Vm + b_));
}
//Real deviative dp/dv at constant temperature
//(molar values)
inline scalar redlichKwong::dpdv(const scalar rho, const scalar T) const
{
scalar Vm = this->W()/rho;
scalar Vm2 = Vm*Vm;
scalar Vm3 = Vm2*Vm;
return
(
a_*(b3_ - 3*b_*Vm2 + 2*Vm3) - this->RR()*pow(T, 1.5)*Vm2*(b2_ + 2*b_*Vm + Vm2)
)
/(sqrt(T)*Vm2*pow((b_ + Vm), 2)*pow( (b_ - Vm), 2));
}
//Real deviative dp/dT at constant molar volume
//(molar values)
inline scalar redlichKwong::dpdT(const scalar rho, const scalar T) const
{
scalar Vm = this->W()/rho;
return 0.5*a_/(pow(T, 1.5)*Vm*(b_ + Vm))-this->RR()/(b_ - Vm);
}
//Real deviative dv/dT at constant pressure
//using implicit differentiation
//(molar values)
inline scalar redlichKwong::dvdT(const scalar rho, const scalar T) const
{
return -this->dpdT(rho, T)/this->dpdv(rho, T);
}
//Real deviative dv/dp at constant temperature
//(molar values)
inline scalar redlichKwong::dvdp(const scalar rho, const scalar T) const
{
return 1/this->dpdv(rho, T);
}
//needed to calculate the internal energy
//(molar values)
inline scalar redlichKwong::integral_p_dv
(
const scalar rho,
const scalar T
) const
{
scalar Vm = this->W()/rho;
return this->RR()*T*log(Vm - b_) + a_/(b_*sqrt(T))*(log(b_ + Vm) - log(Vm));
//return this->RR()*T*log(Vm - b_) + (a_*log(b_ + Vm))/(b_*sqrt(T)) - (a_*log(Vm))/(b_*sqrt(T));
}
//needed to calculate the entropy
//(molar values)
inline scalar redlichKwong::integral_dpdT_dv
(
const scalar rho,
const scalar T
) const
{
scalar Vm = this->W()/rho;
return this->RR()*log(Vm - b_) - a_/(2*b_*pow(T, 1.5))*(log(b_ + Vm) - log(Vm));
//return this->RR()*log(Vm - b_) - (a_*log(b_ + Vm))/(2*b_*T15_) + (a_*log(Vm))/(2*b_*T15_);
}
//(molar values)
inline scalar redlichKwong::d2pdT2(const scalar rho, const scalar T) const
{
scalar Vm = this->W()/rho;
return -0.75*a_/(pow(T, 2.5)*Vm*(b_ + Vm));
}
//(molar values)
inline scalar redlichKwong::d2pdv2(const scalar rho, const scalar T) const
{
scalar Vm = this->W()/rho;
scalar Vm2 = Vm*Vm;
scalar Vm3 = Vm2*Vm;
scalar Vm4 = Vm3*Vm;
scalar Vm5 = Vm4*Vm;
return
(
2*
(
a_*(b5_ - 3*b3_*Vm2 - b2_*Vm3 + 6*b_*Vm4 - 3*Vm5)
+ this->RR()*pow(T, 1.5)*Vm3*(b3_ + 3*b2_*Vm + 3*b_*Vm2 + Vm3)
)
/(sqrt(T)*Vm3*pow((b_ + Vm), 3)*pow(Vm - b_, 3))
);
}
//(molar values)
//using second order implicit differentiation
inline scalar redlichKwong::d2vdT2(const scalar rho, const scalar T) const
{
scalar dpdT2=this->dpdT(rho, T)*this->dpdT(rho, T);
scalar dpdv2=this->dpdv(rho, T)*this->dpdv(rho, T);
scalar dpdv3=dpdv2*this->dpdv(rho, T);
return
-(
dpdT2*this->d2pdv2(rho, T)
+ dpdv2*this->d2pdT2(rho, T)
- 2*this->dpdv(rho, T)*this->dpdT(rho, T)*this->d2pdvdT(rho, T)
)
/dpdv3;
}
//(molar values)
inline scalar redlichKwong::d2pdvdT(const scalar rho, const scalar T) const
{
scalar Vm = this->W()/rho;
scalar Vm2 = Vm*Vm;
scalar Vm3 = Vm2*Vm;
scalar T15_ = pow(T, 1.5);
return
-(
0.5*
(
a_*(b3_ - 3*b_*Vm2 + 2*Vm3)
+ 2*this->RR()*T15_*Vm2*(b2_ + 2*b_*Vm + Vm2)
)
)
/(T15_*Vm2*pow(b_ + Vm, 2)*pow(b_ - Vm, 2));
}
// the result of this intergal is needed for the nasa based cp polynomial
//(molar values)
inline scalar redlichKwong::integral_d2pdT2_dv
(
const scalar rho,
const scalar T
) const
{
scalar T25_=pow(T,2.5);
scalar Vm = this->W()/rho;
return 0.75*a_*log(b_ + Vm)/(T25_*b_) - 0.75*a_*log(Vm)/(T25_*b_);
}
//Isobar expansion Coefficent beta = 1/v (dv/dt) at constant p
//(molar values)
inline scalar redlichKwong::isobarExpCoef
(
const scalar rho,
const scalar T
) const
{
return this->dvdT(rho, T)*rho/this->W();
}
//isothemal compressiblity kappa (not Thermal conductivity)
//(molar values)
inline scalar redlichKwong::isothermalCompressiblity
(
const scalar rho,
const scalar T
) const
{
return this->isobarExpCoef(rho, T)/this->dpdT(rho, T);
//also possible : return -this->dvdp(rho,T)*rho/this->W();
}
//- Return density [kg/m^3]
inline scalar redlichKwong::rho
(
const scalar p,
const scalar T,
const scalar rho0
) const
{
scalar molarVolumePrevIteration;
scalar molarVolume;
label iter = 0;
label maxIter_ = 400;
scalar tol_ = 1e-8;
scalar rho1 = rhoMax_;
scalar rho2 = rhoMin_;
molarVolume = this->W()/rho0;
do
{
molarVolumePrevIteration= molarVolume;
label i=0;
do
{
//CL: modified Newton solver
molarVolume=molarVolumePrevIteration
-(
(this->p((this->W()/molarVolumePrevIteration),T) - p)
/(this->dpdv((this->W()/molarVolumePrevIteration), T))
)/pow(2,i);
i++;
if (i>8)
{
//CL: using bisection methode as backup,
//CL: solution must be between rhoMin_ to rhoMax
for(i=0; i<200; i++)
{
scalar f1 = this->p(rho1, T) - p;
scalar f2 = this->p(rho2, T) - p;
scalar rho3 = (rho1 + rho2)/2;
scalar f3 = this->p(rho3, T) - p;
if ((f2 < 0 && f3 > 0) || (f2 > 0 && f3 < 0))
{
rho1=rho3;
}
else if ((f1 < 0 && f3 > 0)||(f1 > 0 && f3 < 0))
{
rho2=rho3;
}
else
{
rho2=(rho2 + rho3)/2;
}
if(mag(f3) < p*tol_)
{
molarVolume=this->W()/rho3;
molarVolumePrevIteration=this->W()/rho3;
break;
}
else
{
molarVolumePrevIteration=this->W()/rho3;
}
}
}
}
while
(
mag(this->p((this->W()/molarVolume), T) - p)
> mag(this->p((this->W()/molarVolumePrevIteration), T) - p)
);
if (iter++ > maxIter_)
{
FatalErrorIn
(
"inline scalar redlichKwong::rho"
"(const scalar p, const scalar T, const scalar rho0) const "
) << "Maximum number of iterations exceeded"
<< abort(FatalError);
}
}
while(mag(molarVolumePrevIteration-molarVolume) > tol_*(this->W()/rho0));
return this->W()/molarVolume;
}
//- Return density [kg/m^3]
inline scalar redlichKwong::rho(const scalar p, const scalar T) const
{
// using perfect gas equation as starting point
return rho(p, T, p/(this->R()*T));
}
//- Return compressibility drho/dp at T=constant [s^2/m^2]
inline scalar redlichKwong::psi(const scalar rho, const scalar T) const
{
return -this->dvdp(rho, T)*rho*rho/this->W();
}
//- Return compression factor []
inline scalar redlichKwong::Z
(
const scalar p,
const scalar T,
const scalar rho0
) const
{
return p/(this->R()*T*this->rho(p, T, rho0));
}
// * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * //
inline void redlichKwong::operator+=(const redlichKwong& rk)
{
specie::operator+=(rk);
}
inline void redlichKwong::operator*=(const scalar s)
{
specie::operator*=(s);
}
// * * * * * * * * * * * * * * * Friend Operators * * * * * * * * * * * * * //
inline redlichKwong operator+
(
const redlichKwong& rk1,
const redlichKwong& rk2
)
{
return redlichKwong
(
static_cast<const specie&>(rk1)
+ static_cast<const specie&>(rk2)
);
}
inline redlichKwong operator*
(
const scalar s,
const redlichKwong& rk
)
{
return redlichKwong(s*static_cast<const specie&>(rk));
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// ************************************************************************* //

View file

@ -0,0 +1,133 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright held by original author
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM; if not, write to the Free Software Foundation,
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Description
Soave Redlich Kwong equation of state.
Author
Christian Lucas
Institut für Thermodynamik
Technische Universität Braunschweig
Germany
\*---------------------------------------------------------------------------*/
#include "soaveRedlichKwong.H"
#include "IOstreams.H"
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::soaveRedlichKwong::soaveRedlichKwong(Istream& is)
:
specie(is),
pcrit_(readScalar(is)),
Tcrit_(readScalar(is)),
azentricFactor_(readScalar(is)),
a0_(0.42747*pow(this->RR(), 2)*pow(Tcrit_, 2)/pcrit_),
b_(0.08664*this->RR()*Tcrit_/pcrit_),
n_(0.48508 + 1.55171*azentricFactor_ - 0.15613*pow(azentricFactor_, 2)),
b2_(b_*b_),
b3_(b2_*b_),
b5_(b2_*b3_),
//CL: Only uses the default values
rhoMin_(1e-3),
rhoMax_(1500),
// Starting GUESS for the density by ideal gas law
rhostd_(this->rho(this->Pstd(), this->Tstd(), this->Pstd()/(this->Tstd()*this->R()))),
aSave(0.0),
daSave(0.0),
d2aSave(0.0),
TSave(0.0)
{
is.check("soaveRedlichKwong::soaveRedlichKwong(Istream& is)");
}
//CL: Constructed needed in OpenFOAM 2.x.x
//CL: Code works fine, but compiling problem in OpenFOAM 1.6.ext
//CL: because specie has no constructor using dict
/*
soaveRedlichKwong::soaveRedlichKwong(const dictionary& dict)
:
specie(dict),
pcrit_(readScalar(dict.subDict("equationOfState").lookup("pCritical"))),
Tcrit_(readScalar(dict.subDict("equationOfState").lookup("TCritical"))),
azentricFactor_(readScalar(dict.subDict("equationOfState").lookup("azentricFactor"))),
a0_(0.42747*pow(this->RR(), 2)*pow(Tcrit_, 2)/pcrit_),
b_(0.08664*this->RR()*Tcrit_/pcrit_),
n_(0.48508 + 1.55171*azentricFactor_ - 0.15613*pow(azentricFactor_, 2)),
b2_(b_*b_),
b3_(b_*b2_),
b5_(b3_*b2_),
//CL: rhoMin and rhoMax are only used as boundaries for the bisection method (see rho function)
//CL: important: rhoMin and rhoMax are not used as boundary for the newton solver
//CL: therefore, rho can be larger than rhoMax and smaller than rhoMin
rhoMin_(dict.subDict("equationOfState").lookupOrDefault("rhoMin",1e-3)),
rhoMax_(dict.subDict("equationOfState").lookupOrDefault("rhoMax",1500)),
//CL: rhoMin and rhoMax are only used as boundaries for the bisection method (see rho function)
//CL: important: rhoMin and rhoMax are not used as boundary for the newton solver
//CL: therefore, rho can be larger than rhoMax and smaller than rhoMin
rhoMin_(dict.subDict("equationOfState").lookupOrDefault("rhoMin",1e-3)),
rhoMax_(dict.subDict("equationOfState").lookupOrDefault("rhoMax",1500)),
// Starting GUESS for the density by ideal gas law
rhostd_(this->rho(this->Pstd(), this->Tstd(), this->Pstd()/(this->Tstd()*this->R()))),
aSave(0.0),
daSave(0.0),
d2aSave(0.0),
TSave(0.0)
{
is.check("soaveRedlichKwong::soaveRedlichKwong(Istream& is)");
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
void Foam::soaveRedlichKwong::write(Ostream& os) const
{
specie::write(os);
dictionary dict("equationOfState");
dict.add("pCritical", pcrit_);
dict.add("TCritical", Tcrit_);
dict.add("azentricFactor", azentricFactor_);
dict.add("rhoMin", rhoMin_);
dict.add("rhoMax", rhoMax_);
os << indent << dict.dictName() << dict;
}
*/
// * * * * * * * * * * * * * * * Ostream Operator * * * * * * * * * * * * * //
Foam::Ostream& Foam::operator<<(Ostream& os, const soaveRedlichKwong& srk)
{
os << static_cast<const specie&>(srk)<< token::SPACE
<< srk.pcrit_ << tab<< srk.Tcrit_<<tab<<srk.azentricFactor_;
os.check("Ostream& operator<<(Ostream& os, const soaveRedlichKwong& st)");
return os;
}
// ************************************************************************* //

View file

@ -0,0 +1,274 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright held by original author
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM; if not, write to the Free Software Foundation,
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Class
Foam::soaveRedlichKwong
Description
Soave Redlich Kwong equation of state.
Paper:
Title: Equilibrium Constants from a Modified Redlich-Kwong Equation of State
Authors: G. Soave
Journal: Chemical Engineering Science, vol. 27(6), 1972, pp. 1197-1203
SourceFiles
soaveRedlichKwongI.H
soaveRedlichKwong.C
Author
Christian Lucas
Institut für Thermodynamik
Technische Universität Braunschweig
Germany
\*---------------------------------------------------------------------------*/
#ifndef soaveRedlichKwong_H
#define soaveRedlichKwong_H
#include "specie.H"
#include "autoPtr.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
/*---------------------------------------------------------------------------*\
Class Soave Readlich Kwong Declaration
\*---------------------------------------------------------------------------*/
class soaveRedlichKwong
:
public specie
{
// private data
//CL: data at critical point
scalar pcrit_;
scalar Tcrit_;
scalar azentricFactor_;
//-Soave Redlich Kwong
scalar a0_;
scalar b_;
scalar n_;
//CL: pow of constants b_ used in the code e.g. b2_=b*b;
scalar b2_;
scalar b3_;
scalar b5_;
//CL: rhoMin and rhoMax are only used as boundaries for the bisection methode (see rho function)
scalar rhoMin_;
scalar rhoMax_;
//- Density @STD, initialise after a0, b!
scalar rhostd_;
//CL: Variables to save the values of a, dadT and d2adT2 of the mixture
//CL: Variables must corrected for changing temperatures
mutable scalar aSave;
mutable scalar daSave;
mutable scalar d2aSave;
//CL: save the temperature for which the save coefficients (amix,dadTmix,d2adT2mix) are correct
mutable scalar TSave;
//Protected functions
//CL: function updates the coefficients (aSave, daSave, d2aSave)
inline void updateModelCoefficients(const scalar T) const;
public:
// Constructors
//- Construct from components
inline soaveRedlichKwong
(
const specie& sp
);
//- Construct from Istream
soaveRedlichKwong(Istream&);
//- Construct from dictionary
//soaveRedlichKwong(const dictionary& dict);
//- Construct as named copy
inline soaveRedlichKwong(const word& name, const soaveRedlichKwong&);
//- Construct and return a clone
inline autoPtr<soaveRedlichKwong> clone() const;
// Selector from Istream
inline static autoPtr<soaveRedlichKwong> New(Istream& is);
// Member functions
//Return Soave Redlich Kwong factors
inline scalar a0() const;
inline scalar b() const;
inline scalar n() const;
inline scalar rhostd() const;
inline scalar rhoMin() const;
inline scalar rhoMax() const;
inline scalar Tcrit() const;
//CL: Model coefficient a(T)
inline scalar a(const scalar T) const;
//CL: temperature deriviative of model coefficient a(T)
inline scalar dadT(const scalar T) const;
//CL: second order temperature deriviative of model coefficient a(T)
inline scalar d2adT2(const scalar T) const;
//CL: Equation of state
inline scalar p(const scalar rho, const scalar T) const;
//CL: first order derivatives
inline scalar dpdv(const scalar rho, const scalar T) const;
inline scalar dpdT(const scalar rho, const scalar T) const;
inline scalar dvdT(const scalar rho, const scalar T) const;
inline scalar dvdp(const scalar rho, const scalar T) const;
inline scalar isobarExpCoef(const scalar rho, const scalar T) const;
inline scalar isothermalCompressiblity
(
const scalar rho,
const scalar T
) const;
//CL: Used for cv
inline scalar integral_d2pdT2_dv
(
const scalar rho,
const scalar T
) const;
//CL: second order derivatives, not Used At The Moment
inline scalar d2pdv2(const scalar rho, const scalar T) const;
inline scalar d2pdT2(const scalar rho, const scalar T) const;
inline scalar d2pdvdT(const scalar rho, const scalar T) const;
inline scalar d2vdT2(const scalar rho, const scalar T) const;
//CL: Used for internal Energy
inline scalar integral_p_dv
(
const scalar rho,
const scalar T
) const;
//CL: Used for Entropy
inline scalar integral_dpdT_dv
(
const scalar rho,
const scalar T
) const;
//- Return density [kg/m^3]
// rho0 is the starting point of the newton solver used to calculate rho
inline scalar rho
(
const scalar p,
const scalar T,
const scalar rho0
) const;
inline scalar rho(const scalar p, const scalar T) const;
//- Return compressibility drho/dp at T=constant [s^2/m^2]
inline scalar psi(const scalar rho, const scalar T) const;
//- Return compression factor []
inline scalar Z
(
const scalar p,
const scalar T,
const scalar rho0
) const;
// I-O
//- Write to Ostream
//void write(Ostream& os) const;
// Member operators
inline void operator+=(const soaveRedlichKwong&);
inline void operator*=(const scalar);
// Friend operators
inline friend soaveRedlichKwong operator+
(
const soaveRedlichKwong&,
const soaveRedlichKwong&
);
inline friend soaveRedlichKwong operator*
(
const scalar s,
const soaveRedlichKwong&
);
// Ostream Operator
friend Ostream& operator<<(Ostream&, const soaveRedlichKwong&);
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#include "soaveRedlichKwongI.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View file

@ -0,0 +1,544 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright held by original author
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM; if not, write to the Free Software Foundation,
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Author
Christian Lucas
Institut für Thermodynamik
Technische Universität Braunschweig
Germany
\*---------------------------------------------------------------------------*/
#include "soaveRedlichKwong.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
// Construct from components
inline soaveRedlichKwong::soaveRedlichKwong
(
const specie& sp
)
:
specie(sp),
TSave(0)
{}
// Construct as named copy
inline soaveRedlichKwong::soaveRedlichKwong(const word& name, const soaveRedlichKwong& srk)
:
specie(name, srk),
pcrit_(srk.pcrit_),
Tcrit_(srk.Tcrit_),
azentricFactor_(srk.azentricFactor_),
a0_(srk.a0_),
b_(srk.b_),
n_(srk.n_),
b2_(srk.b2_),
b3_(srk.b3_),
b5_(srk.b5_),
rhoMin_(srk.rhoMin_),
rhoMax_(srk.rhoMax_),
rhostd_(srk.rhostd_),
aSave(0.0),
daSave(0.0),
d2aSave(0.0),
TSave(0.0)
{}
// Construct and return a clone
inline autoPtr<soaveRedlichKwong> soaveRedlichKwong::clone() const
{
return autoPtr<soaveRedlichKwong>(new soaveRedlichKwong(*this));
}
// Selector from Istream
inline autoPtr<soaveRedlichKwong> soaveRedlichKwong::New(Istream& is)
{
return autoPtr<soaveRedlichKwong>(new soaveRedlichKwong(is));
}
// * * * * * * * * * * * * * Member Functions * * * * * * * * * * * //
inline scalar soaveRedlichKwong::rhostd() const
{
return rhostd_;
}
inline scalar soaveRedlichKwong::rhoMin() const
{
return rhoMin_;
}
inline scalar soaveRedlichKwong::rhoMax() const
{
return rhoMax_;
}
inline scalar soaveRedlichKwong::Tcrit() const
{
return Tcrit_;
}
inline void soaveRedlichKwong::updateModelCoefficients(const scalar T) const
{
aSave=a0_*pow(1 + n_*(1 - pow(T/Tcrit_, 0.5)), 2);
daSave=a0_*n_*(n_*sqrt(T/Tcrit_) - n_ - 1)*sqrt(T/Tcrit_)/T;
d2aSave=a0_*n_*(n_ + 1)*sqrt(T/Tcrit_)/(2*T*T);
//CL: saving the temperature at which the coefficients are valid
TSave=T;
}
//CL: Model coefficient a(T)
inline scalar soaveRedlichKwong::a(const scalar T) const
{
//CL: check if a has already been calculated for this temperature
if(TSave==T)
{
return aSave;
}
//CL: If not, recalculate a(T), dadT(T) and d2adT2(T)
else
{
updateModelCoefficients(T);
return aSave;
}
}
//CL: temperature deriviative of model coefficient a(T)
inline scalar soaveRedlichKwong::dadT(const scalar T) const
{
// check if a has already been calculated for this temperature
if(TSave==T)
{
return daSave;
}
//CL: If not, recalculate a(T), dadT(T) and d2adT2(T)
else
{
updateModelCoefficients(T);
return daSave;
}
}
//CL: second order temperature deriviative of model coefficient a(T)
inline scalar soaveRedlichKwong::d2adT2(const scalar T) const
{
// check if a has already been calculated for this temperature
if(TSave==T)
{
return d2aSave;
}
//CL: If not, recalculate a(T), dadT(T) and d2adT2(T)
else
{
updateModelCoefficients(T);
return d2aSave;
}
}
inline scalar soaveRedlichKwong::a0() const
{
return a0_;
}
inline scalar soaveRedlichKwong::b() const
{
return b_;
}
inline scalar soaveRedlichKwong::n() const
{
return n_;
}
//returns the pressure for a given density and temperature
inline scalar soaveRedlichKwong::p(const scalar rho, const scalar T) const
{
scalar Vm = this->W()/rho;
return this->RR()*T/(Vm - b_) - a(T)/(Vm*(Vm + b_));
}
//Real deviative dp/dv at constant temperature
//(molar values)
inline scalar soaveRedlichKwong::dpdv(const scalar rho, const scalar T) const
{
scalar Vm = this->W()/rho;
scalar Vm2 = Vm*Vm;
scalar Vm3 = Vm2*Vm;
return
(
a(T)*(b3_ - 3*b_*Vm2 + 2*Vm3) - this->RR()*T*Vm2*(b2_ + 2*b_*Vm + Vm2)
)
/(Vm2*pow(b_ + Vm, 2)*pow(b_ - Vm, 2));
}
//Real deviative dp/dT at constant molar volume
//(molar values)
inline scalar soaveRedlichKwong::dpdT(const scalar rho, const scalar T) const
{
scalar Vm = this->W()/rho;
return this->RR()/(Vm - b_) - dadT(T)/(Vm*(Vm + b_));
}
//Real deviative dv/dT at constant pressure
//using implicit differentiation
// (molar values)
inline scalar soaveRedlichKwong::dvdT(const scalar rho, const scalar T) const
{
return -this->dpdT(rho, T)/this->dpdv(rho, T);
}
//Real deviative dv/dp at constant temperature
//(molar values)
inline scalar soaveRedlichKwong::dvdp(const scalar rho, const scalar T) const
{
return 1/this->dpdv(rho, T);
}
//needed to calculate the internal energy
//(molar values)
inline scalar soaveRedlichKwong::integral_p_dv
(
const scalar rho,
const scalar T
) const
{
scalar Vm = this->W()/rho;
return this->RR()*T*log(Vm - b_) + a(T)/b_*(log(b_ + Vm) - log(Vm));
//return this->RR()*T*log(Vm - b_) + a(T)*log(b_ + Vm)/b_ - a(T)*log(Vm)/b_;
}
//needed to calculate the entropy
//(molar values)
//needed to calculate the entropy
inline scalar soaveRedlichKwong::integral_dpdT_dv
(
const scalar rho,
const scalar T
) const
{
scalar Vm = this->W()/rho;
return this->RR()*log(Vm - b_) + dadT(T)/b_*(log(b_ + Vm) - log(Vm));
//return this->RR()*log(Vm - b_) + dadT(T)*log(b_ + Vm)/b_ - dadT(T)*log(Vm)/b_;
}
//(molar values)
inline scalar soaveRedlichKwong::d2pdT2(const scalar rho, const scalar T) const
{
scalar Vm = this->W()/rho;
return -d2adT2(T)/(Vm*(Vm + b_));
}
//(molar values)
inline scalar soaveRedlichKwong::d2pdv2(const scalar rho, const scalar T) const
{
scalar Vm = this->W()/rho;
scalar Vm2 = Vm*Vm;
scalar Vm3 = Vm2*Vm;
scalar Vm4 = Vm3*Vm;
scalar Vm5 = Vm4*Vm;
return 2*
(
a(T)*(b5_ - 3*b3_*Vm2 - b2_*Vm3 + 6*b_*Vm4 - 3*Vm5)
+ this->RR()*T*Vm3*(b3_ + 3*b2_*Vm + 3*b_*Vm2 + Vm3)
)
/(Vm3*pow(b_ + Vm, 3)*pow(Vm - b_, 3));
}
//(molar values)
//using second order implicit differentiation
inline scalar soaveRedlichKwong::d2vdT2
(
const scalar rho,
const scalar T
) const
{
scalar dpdT2=this->dpdT(rho, T)*this->dpdT(rho, T);
scalar dpdv2=this->dpdv(rho, T)*this->dpdv(rho, T);
scalar dpdv3=dpdv2*this->dpdv(rho, T);
return
-(
dpdT2*this->d2pdv2(rho, T)
+ dpdv2*this->d2pdT2(rho, T)
- 2*this->dpdv(rho, T)*this->dpdT(rho, T)*this->d2pdvdT(rho, T)
)
/dpdv3;
}
//(molar values)
inline scalar soaveRedlichKwong::d2pdvdT
(
const scalar rho,
const scalar T
) const
{
scalar Vm = this->W()/rho;
scalar Vm2 = Vm*Vm;
scalar Vm3 = Vm2*Vm;
return
(
dadT(T)*(b3_ - 3*b_*Vm2 + 2*Vm3) - this->RR()*Vm2*(b2_ + 2*b_*Vm + Vm2)
)
/(Vm2*pow(b_ + Vm, 2)*pow(b_ - Vm, 2));
}
// the result of this intergal is needed for the nasa based cp polynomial
//(molar values)
inline scalar soaveRedlichKwong::integral_d2pdT2_dv
(
const scalar rho,
const scalar T
) const
{
scalar Vm = this->W()/rho;
return d2adT2(T)*log(b_ + Vm)/b_ - d2adT2(T)*log(Vm)/b_;
}
//Isobar expansion Coefficent beta = 1/v (dv/dt) at constant p
//(molar values)
inline scalar soaveRedlichKwong::isobarExpCoef
(
const scalar rho,
const scalar T
) const
{
return this->dvdT(rho, T)*rho/this->W();
}
//isothemal compressiblity kappa (not Thermal conductivity)
//(molar values)
inline scalar soaveRedlichKwong::isothermalCompressiblity
(
const scalar rho,
const scalar T
) const
{
return this->isobarExpCoef(rho, T)/this->dpdT(rho, T);
//CL: also possible
//CL: return -this->dvdp(rho, T)*rho/this->W();
}
//- Return density [kg/m^3]
inline scalar soaveRedlichKwong::rho
(
const scalar p,
const scalar T,
const scalar rho0
) const
{
scalar molarVolumePrevIteration;
scalar molarVolume;
label iter = 0;
label maxIter_ = 400;
scalar tol_ = 1e-8;
scalar rho1 = rhoMax_;
scalar rho2 = rhoMin_;
molarVolume = this->W()/rho0;
do
{
molarVolumePrevIteration= molarVolume;
label i=0;
do
{
//CL: modified Newton solver
molarVolume=molarVolumePrevIteration
-(
(this->p((this->W()/molarVolumePrevIteration),T) - p)
/(this->dpdv((this->W()/molarVolumePrevIteration), T))
)/pow(2,i);
i++;
if (i>8)
{
//CL: using bisection methode as backup,
//CL: solution must be between rhoMin_ to rhoMax
for(i=0; i<200; i++)
{
scalar f1 = this->p(rho1, T) - p;
scalar f2 = this->p(rho2, T) - p;
scalar rho3 = (rho1 + rho2)/2;
scalar f3 = this->p(rho3, T) - p;
if ((f2 < 0 && f3 > 0) || (f2 > 0 && f3 < 0))
{
rho1=rho3;
}
else if ((f1 < 0 && f3 > 0)||(f1 > 0 && f3 < 0))
{
rho2=rho3;
}
else
{
rho2=(rho2 + rho3)/2;
}
if(mag(f3) < p*tol_)
{
molarVolume=this->W()/rho3;
molarVolumePrevIteration=this->W()/rho3;
break;
}
else
{
molarVolumePrevIteration=this->W()/rho3;
}
}
}
}
while
(
mag(this->p((this->W()/molarVolume), T) - p)
> mag(this->p((this->W()/molarVolumePrevIteration), T) - p)
);
if (iter++ > maxIter_)
{
FatalErrorIn
(
"inline scalar soaveRedlichKwong::rho"
"(const scalar p, const scalar T, const scalar rho0) const "
) << "Maximum number of iterations exceeded"
<< abort(FatalError);
}
}
while(mag(molarVolumePrevIteration-molarVolume) > tol_*(this->W()/rho0));
return this->W()/molarVolume;
}
//- Return density [kg/m^3]
inline scalar soaveRedlichKwong::rho(const scalar p, const scalar T) const
{
//CL: using perfect gas equation as starting point
return rho(p, T, p/(this->R()*T));
}
//- Return compressibility drho/dp at T=constant [s^2/m^2]
inline scalar soaveRedlichKwong::psi(const scalar rho, const scalar T) const
{
return -this->dvdp(rho, T)*rho*rho/this->W();
}
//- Return compression factor []
inline scalar soaveRedlichKwong::Z
(
const scalar p,
const scalar T,
const scalar rho0
) const
{
return p/(this->R()*T*this->rho(p, T, rho0));
}
// * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * //
inline void soaveRedlichKwong::operator+=(const soaveRedlichKwong& srk)
{
specie::operator+=(srk);
}
inline void soaveRedlichKwong::operator*=(const scalar s)
{
specie::operator*=(s);
}
// * * * * * * * * * * * * * * * Friend Operators * * * * * * * * * * * * * //
inline soaveRedlichKwong operator+
(
const soaveRedlichKwong& srk1,
const soaveRedlichKwong& srk2
)
{
return soaveRedlichKwong
(
static_cast<const specie&>(srk1)
+ static_cast<const specie&>(srk2)
);
}
inline soaveRedlichKwong operator*
(
const scalar s,
const soaveRedlichKwong& srk
)
{
return soaveRedlichKwong(s*static_cast<const specie&>(srk));
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// ************************************************************************* //

View file

@ -0,0 +1,71 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | foam-extend: Open Source CFD
\\ / O peration |
\\ / A nd | For copyright notice see file Copyright
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of foam-extend.
foam-extend is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation, either version 3 of the License, or (at your
option) any later version.
foam-extend is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with foam-extend. If not, see <http://www.gnu.org/licenses/>.
Author
Christian Lucas
Institut für Thermodynamik
Technische Universität Braunschweig
Germany
\*---------------------------------------------------------------------------*/
#include "constantHeatCapacity.H"
#include "IOstreams.H"
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
template<class equationOfState>
Foam::constantHeatCapacity<equationOfState>::constantHeatCapacity(Istream& is)
:
equationOfState(is),
Cp0_(readScalar(is)),
cp0_(Cp0_*this->W()),
//values for some need terms at std
e0_std(e0(this->Tstd())),
s0_std(s0(this->Tstd())),
integral_p_dv_std(this->integral_p_dv(this->rhostd(),this->Tstd())),
integral_dpdT_dv_std(this->integral_dpdT_dv(this->rhostd(),this->Tstd())),
// cp @ STD (needed to limit cp for stability
cp_std(this->cp_nonLimited(this->rhostd(),this->Tstd()))
{
is.check("constantHeatCapacity::constantHeatCapacity(Istream& is)");
}
// * * * * * * * * * * * * * * * Ostream Operator * * * * * * * * * * * * * //
template<class equationOfState>
Foam::Ostream& Foam::operator<<
(
Ostream& os,
const constantHeatCapacity<equationOfState>& np
)
{
os << static_cast<const equationOfState&>(np) << tab
<< np.Cp0_;
os.check("Ostream& operator<<(Ostream& os, const constantHeatCapacity& np)");
return os;
}
// ************************************************************************* //

View file

@ -0,0 +1,256 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | foam-extend: Open Source CFD
\\ / O peration |
\\ / A nd | For copyright notice see file Copyright
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of foam-extend.
foam-extend is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation, either version 3 of the License, or (at your
option) any later version.
foam-extend is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with foam-extend. If not, see <http://www.gnu.org/licenses/>.
Class
Foam::constantHeatCapacity
Description
real gas thermodynamic class --> constant perfect gas heat capacity
Important: the perfect gas heat capacity is constant, the real heat capacity is not constant due to real gas corrections
templated into the equationOfState
-> uses the equation of state to calculate all real Gas properties like Enthalpy, Entropy ...
-> can not be used with the perfectGas equation of state
Equations for the real gas correction: Have a look at thermodnamics books e.g. Thermodynamics:
An Engineering Approch, 5 Edition, Chapter 12
SourceFiles
constantHeatCapacityI.H
constantHeatCapacity.C
Author
Christian Lucas
Institut für Thermodynamik
Technische Universität Braunschweig
Germany
\*---------------------------------------------------------------------------*/
#ifndef constantHeatCapacity_H
#define constantHeatCapacity_H
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
// Forward declaration of friend functions and operators
template<class equationOfState> class constantHeatCapacity;
template<class equationOfState>
inline constantHeatCapacity<equationOfState> operator+
(
const constantHeatCapacity<equationOfState>&,
const constantHeatCapacity<equationOfState>&
);
template<class equationOfState>
inline constantHeatCapacity<equationOfState> operator-
(
const constantHeatCapacity<equationOfState>&,
const constantHeatCapacity<equationOfState>&
);
template<class equationOfState>
inline constantHeatCapacity<equationOfState> operator*
(
const scalar,
const constantHeatCapacity<equationOfState>&
);
template<class equationOfState>
inline constantHeatCapacity<equationOfState> operator==
(
const constantHeatCapacity<equationOfState>&,
const constantHeatCapacity<equationOfState>&
);
template<class equationOfState>
Ostream& operator<<
(
Ostream&,
const constantHeatCapacity<equationOfState>&
);
/*---------------------------------------------------------------------------*\
Class constantHeatCapacity Thermo Declaration
\*---------------------------------------------------------------------------*/
template<class equationOfState>
class constantHeatCapacity
:
public equationOfState
{
// Private data
//CL: spec. cp
scalar Cp0_;
//CL: molar values
scalar cp0_;
scalar e0_std;
scalar s0_std;
scalar integral_p_dv_std;
scalar integral_dpdT_dv_std;
scalar cp_std;
// Private member functions
//- Construct from components
//CL: used for the operator+
inline constantHeatCapacity
(
const equationOfState& st,
const scalar cp0_
);
//- Construct from components
//CL: used for the operator*
inline constantHeatCapacity
(
const equationOfState& st,
const scalar cp0_,
const scalar e0_std_,
const scalar s0_std_,
const scalar integral_p_dv_std_,
const scalar integral_dpdT_dv_std_,
const scalar cp_std_
);
public:
//Variable
// Constructors
//- Construct from Istream
constantHeatCapacity(Istream&);
//- Construct as named copy
inline constantHeatCapacity(const word&, const constantHeatCapacity&);
//- Construct and return a clone
inline autoPtr<constantHeatCapacity> clone() const;
//- Selector from Istream
inline static autoPtr<constantHeatCapacity> New(Istream& is);
// Member Functions
//- perfect Gas Enthalpy [J/kmol]
inline scalar h0(const scalar T) const;
//- perfect Gas Entropy [J/(kmol K)]
inline scalar s0(const scalar T) const;
//- perfect Gas internal Energy [J/kmol]
inline scalar e0(const scalar T) const;
//- perfect gas Heat capacity at constant pressure [J/(kmol K)]
inline scalar cv0(const scalar T) const;
//- perfect gas Heat capacity at constant pressure [J/(kmol K)]
inline scalar cp0(const scalar T) const;
//- Limited Heat capacity at constant pressure [J/(kmol K)]
inline scalar cp(const scalar rho, const scalar T) const;
//- non Limited Heat capacity at constant pressure [J/(kmol K)]
inline scalar cp_nonLimited(const scalar rho, const scalar T) const;
//- Heat capacity at constant pressure [J/(kmol K)]
inline scalar cv(const scalar rho, const scalar T) const;
//- Enthalpy [J/kmol]
inline scalar h(const scalar rho, const scalar T) const;
//- Entropy [J/(kmol K)]
inline scalar s(const scalar rho,const scalar T) const;
//- Internal Energy [J/kmol]
inline scalar e(const scalar rho, const scalar T) const;
// Member operators
inline void operator+=(const constantHeatCapacity&);
inline void operator-=(const constantHeatCapacity&);
// Friend operators
friend constantHeatCapacity operator+ <equationOfState>
(
const constantHeatCapacity&,
const constantHeatCapacity&
);
friend constantHeatCapacity operator- <equationOfState>
(
const constantHeatCapacity&,
const constantHeatCapacity&
);
friend constantHeatCapacity operator* <equationOfState>
(
const scalar,
const constantHeatCapacity&
);
friend constantHeatCapacity operator== <equationOfState>
(
const constantHeatCapacity&,
const constantHeatCapacity&
);
// IOstream Operators
friend Ostream& operator<< <equationOfState>
(
Ostream&,
const constantHeatCapacity&
);
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#include "constantHeatCapacityI.H"
#ifdef NoRepository
# include "constantHeatCapacity.C"
#endif
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View file

@ -0,0 +1,407 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | foam-extend: Open Source CFD
\\ / O peration |
\\ / A nd | For copyright notice see file Copyright
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of foam-extend.
foam-extend is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation, either version 3 of the License, or (at your
option) any later version.
foam-extend is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with foam-extend. If not, see <http://www.gnu.org/licenses/>.
Author
Christian Lucas
Institut für Thermodynamik
Technische Universität Braunschweig
Germany
\*---------------------------------------------------------------------------*/
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
//- Construct from components
//CL: used for the operator+
template<class equationOfState>
inline Foam::constantHeatCapacity<equationOfState>::constantHeatCapacity
(
const equationOfState& st,
const scalar cp0_
)
:
equationOfState(st),
cp0_(cp0_),
e0_std(e0(this->Tstd)),
s0_std(s0(this->Tstd)),
integral_p_dv_std(this->integral_p_dv(this->rhostd(),this->Tstd)),
integral_dpdT_dv_std(this->integral_dpdT_dv(this->rhostd(),this->Tstd)),
cp_std(this->cp_nonLimited(this->rhostd(),this->Tstd))
{}
//- Construct from components
//CL: used for the operator*
template<class equationOfState>
inline Foam::constantHeatCapacity<equationOfState>::constantHeatCapacity
(
const equationOfState& st,
const scalar cp0_,
const scalar e0_std_,
const scalar s0_std_,
const scalar integral_p_dv_std_,
const scalar integral_dpdT_dv_std_,
const scalar cp_std_
)
:
equationOfState(st),
cp0_(cp0_),
e0_std(e0_std_),
s0_std(s0_std_),
integral_p_dv_std(integral_p_dv_std_),
integral_dpdT_dv_std(integral_dpdT_dv_std_),
cp_std(cp_std_)
{}
template<class equationOfState>
inline Foam::constantHeatCapacity<equationOfState>::constantHeatCapacity
(
const word& name,
const constantHeatCapacity& np
)
:
equationOfState(name, np),
cp0_(np.cp0_),
e0_std(np.e0_std),
s0_std(np.s0_std),
integral_p_dv_std(np.integral_p_dv_std),
integral_dpdT_dv_std(np.integral_dpdT_dv_std),
cp_std(np.cp_std)
{}
template<class equationOfState>
inline Foam::autoPtr<Foam::constantHeatCapacity<equationOfState> >
Foam::constantHeatCapacity<equationOfState>::clone() const
{
return autoPtr<constantHeatCapacity<equationOfState> >
(
new constantHeatCapacity<equationOfState>(*this)
);
}
template<class equationOfState>
inline Foam::autoPtr<Foam::constantHeatCapacity<equationOfState> >
Foam::constantHeatCapacity<equationOfState>::New(Istream& is)
{
return autoPtr<constantHeatCapacity<equationOfState> >
(
new constantHeatCapacity<equationOfState>(is)
);
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
//used to calculate the internal energy
//perfect gas enthalpy
template<class equationOfState>
inline Foam::scalar Foam::constantHeatCapacity<equationOfState>::h0
(
const scalar T
) const
{
return cp0_*T;
}
//used to calculate the internal energy
//perfect gas internal energy
template<class equationOfState>
inline Foam::scalar Foam::constantHeatCapacity<equationOfState>::e0
(
const scalar T
) const
{
return this->h0(T) - this->RR()*T;
}
// used to calculate the entropy
// perfect gas entropy
template<class equationOfState>
inline Foam::scalar Foam::constantHeatCapacity<equationOfState>::s0
(
const scalar T
) const
{
return cp0_*log(T);
}
//perfect gas cp
template<class equationOfState>
inline Foam::scalar Foam::constantHeatCapacity<equationOfState>::cp0
(
const scalar T
) const
{
return cp0_;
}
//perfect gas cv
template<class equationOfState>
inline Foam::scalar Foam::constantHeatCapacity<equationOfState>::cv0
(
const scalar T
) const
{
return this->cp0(T)-this->RR();
}
//function to calculate real gas cp
//using cp=cv+(dp/dT)^2/(dp/dv)
template<class equationOfState>
inline Foam::scalar Foam::constantHeatCapacity<equationOfState>::cp
(
const scalar rho,
const scalar T
) const
{
// Problem --> dpdv(rho,T) is =0 at some points within the vapour dome. To increase stability, (dp/dv) has to be limited
// cp can be negative within the vapor dome. To avoid this nonphysical result, the absolute value is used.
// within the vapourdome and at the critical point, cp increases to very high values --> infinity,
// this would decrease the stability, so cp will be limited to 20 times the cp @ STD
return
min
(
cp_std*20,
fabs
(
this->cv(rho,T)
- T*pow((this->dpdT(rho, T)), 2)/min(this->dpdv(rho, T), -1)
)
);
}
// this function is needed to get cp @ STD (without the limit imposed in the function above),
// which in turn is needed to limit the cp in the function above
template<class equationOfState>
inline Foam::scalar Foam::constantHeatCapacity<equationOfState>::cp_nonLimited
(
const scalar rho,
const scalar T
) const
{
return
fabs(this->cv(rho, T)
- T*pow((this->dpdT(rho, T)), 2)/min(this->dpdv(rho, T), -1));
}
//function to calculate real gas c
//cv=cv0+T*integral d2p/dT2 dv
template<class equationOfState>
inline Foam::scalar Foam::constantHeatCapacity<equationOfState>::cv
(
const scalar rho,
const scalar T
) const
{
return this->cv0(T) + T*this->integral_d2pdT2_dv(rho, T);
}
//function to calculate real gas enthalpy
template<class equationOfState>
inline Foam::scalar Foam::constantHeatCapacity<equationOfState>::h
(
const scalar rho,
const scalar T
) const
{
return
this->e(rho, T)
+ this->p(rho, T)/rho*this->W()
- this->Pstd()/this->rhostd()*this->W();
}
// function to calculate real gas internal energy
// important assumption used: internal Energie is 0 at STD conditions.
// equation: du= cv0 dT +[T*dp/dT -p]dv
template<class equationOfState>
inline Foam::scalar Foam::constantHeatCapacity<equationOfState>::e
(
const scalar rho,
const scalar T
) const
{
return
- this->Tstd()*integral_dpdT_dv_std
+ integral_p_dv_std
+ this->e0(T)
- e0_std
+ T*this->integral_dpdT_dv(rho, T)
- this->integral_p_dv(rho, T);
}
//function to calculate real gas entropy
// important assumption used: the Entropy is 0 at STD conditions.
// equation: ds= cv0/T * dT + dp/dT *dv
// --> integral cv0/T dT = s0(T) -s0(Tstd) - R*ln(T/Tstd) --> due to s0(T)-s0(Tstd)=integral cp0/T dT
template<class equationOfState>
inline Foam::scalar Foam::constantHeatCapacity<equationOfState>::s
(
const scalar rho,
const scalar T
) const
{
return
- integral_dpdT_dv_std
+ this->s0(T)
- s0_std
- this->RR*log(T/this->Tstd())
+ this->integral_dpdT_dv(rho, T);
}
// * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * //
template<class equationOfState>
inline void Foam::constantHeatCapacity<equationOfState>::operator+=
(
const constantHeatCapacity<equationOfState>& np
)
{
scalar molr1 = this->nMoles();
equationOfState::operator+=(np);
molr1 /= this->nMoles();
scalar molr2 = np.nMoles()/this->nMoles();
cp0_ = molr1*cp0_ + molr2*np.cp0_;
}
template<class equationOfState>
inline void Foam::constantHeatCapacity<equationOfState>::operator-=
(
const constantHeatCapacity<equationOfState>& np
)
{
scalar molr1 = this->nMoles();
constantHeatCapacity::operator-=(np);
molr1 /= this->nMoles();
scalar molr2 = np.nMoles()/this->nMoles();
cp0_ = molr1*cp0_ - molr2*np.cp0_;
}
// * * * * * * * * * * * * * * * Friend Operators * * * * * * * * * * * * * //
template<class equationOfState>
inline Foam::constantHeatCapacity<equationOfState> Foam::operator+
(
const constantHeatCapacity<equationOfState>& np1,
const constantHeatCapacity<equationOfState>& np2
)
{
equationOfState eofs
(
static_cast<const equationOfState&>(np1)
+ static_cast<const equationOfState&>(np2)
);
//CL: Important, calls a different constructor as operator*
//CL: the coefficients as well as the EOS (coefficients) changed
//CL: therefore, the values at STD needs to be recalculated
return constantHeatCapacity<equationOfState>
(
eofs,
np1.nMoles()/eofs.nMoles()*np1.cp0_
+ np2.nMoles()/eofs.nMoles()*np2.cp0_
);
}
template<class equationOfState>
inline Foam::constantHeatCapacity<equationOfState> Foam::operator-
(
const constantHeatCapacity<equationOfState>& np1,
const constantHeatCapacity<equationOfState>& np2
)
{
equationOfState eofs
(
static_cast<const equationOfState&>(np1)
- static_cast<const equationOfState&>(np2)
);
return constantHeatCapacity<equationOfState>
(
eofs,
np1.nMoles()/eofs.nMoles()*np1.cp0_
- np2.nMoles()/eofs.nMoles()*np2.cp0_
);
}
template<class equationOfState>
inline Foam::constantHeatCapacity<equationOfState> Foam::operator*
(
const scalar s,
const constantHeatCapacity<equationOfState>& np
)
{
//CL: values at STD don't need to be recalculated,
//CL: therefore, providing the values in the constructor
return constantHeatCapacity<equationOfState>
(
s*static_cast<const equationOfState&>(np),
np.cp0_,
np.e0_std,
np.s0_std,
np.integral_p_dv_std,
np.integral_dpdT_dv_std,
np.cp_std
);
}
template<class equationOfState>
inline Foam::constantHeatCapacity<equationOfState> Foam::operator==
(
const constantHeatCapacity<equationOfState>& np1,
const constantHeatCapacity<equationOfState>& np2
)
{
return np2 - np1;
}
// ************************************************************************* //

View file

@ -0,0 +1,77 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd |
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM; if not, write to the Free Software Foundation,
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Author
Christian Lucas
Institut für Thermodynamik
Technische Universität Braunschweig
Germany
\*---------------------------------------------------------------------------*/
#include "nasaHeatCapacityPolynomial.H"
#include "IOstreams.H"
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
template<class equationOfState>
Foam::nasaHeatCapacityPolynomial<equationOfState>::nasaHeatCapacityPolynomial(Istream& is)
:
equationOfState(is),
a1_(readScalar(is)),
a2_(readScalar(is)),
a3_(readScalar(is)),
a4_(readScalar(is)),
a5_(readScalar(is)),
a6_(readScalar(is)),
a7_(readScalar(is)),
//values for some need terms at std
e0_std(e0(this->Tstd())),
s0_std(s0(this->Tstd())),
integral_p_dv_std(this->integral_p_dv(this->rhostd(),this->Tstd())),
integral_dpdT_dv_std(this->integral_dpdT_dv(this->rhostd(),this->Tstd())),
//cp @ STD (needed to limit cp for stability
cp_std(this->cp_nonLimited(this->rhostd(),this->Tstd()))
{
is.check("nasaHeatCapacityPolynomial::nasaHeatCapacityPolynomial(Istream& is)");
}
// * * * * * * * * * * * * * * * Ostream Operator * * * * * * * * * * * * * //
template<class equationOfState>
Foam::Ostream& Foam::operator<<
(
Ostream& os,
const nasaHeatCapacityPolynomial<equationOfState>& np
)
{
os << static_cast<const equationOfState&>(np) << tab
<< np.a1_ << tab<< np.a2_ << tab << np.a3_ << tab << np.a4_ << tab << np.a5_ << tab << np.a6_ << tab << np.a7_ ;
os.check("Ostream& operator<<(Ostream& os, const nasaHeatCapacityPolynomial& np)");
return os;
}
// ************************************************************************* //

View file

@ -0,0 +1,275 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd |
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM; if not, write to the Free Software Foundation,
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Class
Foam::nasaHeatCapacityPolynomial
Description
Nasa Heat Capacity Polynomial for perfect Gas (7.order polynominal) --> freely available for many fluids
--> paper title: NASA Glenn Coefficients for Calculating Thermodynamic Properties of Individual Species
templated into the equationOfState
-> uses the equation of state to calculate all real Gas properties like Enthalpy, Entropy ...
-> can not be used with the perfectGas equation of state
Equations for the real gas correction: Have a look at thermodnamics books e.g. Thermodynamics: An Engineering Approch, 5 Edition, Chapter 12
SourceFiles
nasaHeatCapacityPolynomialI.H
nasaHeatCapacityPolynomial.C
Author
Christian Lucas
Institut für Thermodynamik
Technische Universität Braunschweig
Germany
\*---------------------------------------------------------------------------*/
#ifndef nasaHeatCapacityPolynomial_H
#define nasaHeatCapacityPolynomial_H
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
// Forward declaration of friend functions and operators
template<class equationOfState> class nasaHeatCapacityPolynomial;
template<class equationOfState>
inline nasaHeatCapacityPolynomial<equationOfState> operator+
(
const nasaHeatCapacityPolynomial<equationOfState>&,
const nasaHeatCapacityPolynomial<equationOfState>&
);
template<class equationOfState>
inline nasaHeatCapacityPolynomial<equationOfState> operator-
(
const nasaHeatCapacityPolynomial<equationOfState>&,
const nasaHeatCapacityPolynomial<equationOfState>&
);
template<class equationOfState>
inline nasaHeatCapacityPolynomial<equationOfState> operator*
(
const scalar,
const nasaHeatCapacityPolynomial<equationOfState>&
);
template<class equationOfState>
inline nasaHeatCapacityPolynomial<equationOfState> operator==
(
const nasaHeatCapacityPolynomial<equationOfState>&,
const nasaHeatCapacityPolynomial<equationOfState>&
);
template<class equationOfState>
Ostream& operator<<
(
Ostream&,
const nasaHeatCapacityPolynomial<equationOfState>&
);
/*---------------------------------------------------------------------------*\
Class nasaHeatCapacityPolynomial Thermo Declaration
\*---------------------------------------------------------------------------*/
template<class equationOfState>
class nasaHeatCapacityPolynomial
:
public equationOfState
{
// Private data
scalar a1_;
scalar a2_;
scalar a3_;
scalar a4_;
scalar a5_;
scalar a6_;
scalar a7_;
scalar e0_std;
scalar s0_std;
scalar integral_p_dv_std;
scalar integral_dpdT_dv_std;
scalar cp_std;
// Private member functions
//- Construct from components
//CL: used for the operator+
inline nasaHeatCapacityPolynomial
(
const equationOfState& st,
const scalar a1,
const scalar a2,
const scalar a3,
const scalar a4,
const scalar a5,
const scalar a6,
const scalar a7
);
//- Construct from components
//CL: used for the operator*
inline nasaHeatCapacityPolynomial
(
const equationOfState& st,
const scalar a1,
const scalar a2,
const scalar a3,
const scalar a4,
const scalar a5,
const scalar a6,
const scalar a7,
const scalar e0_std_,
const scalar s0_std_,
const scalar integral_p_dv_std_,
const scalar integral_dpdT_dv_std_,
const scalar cp_std_
);
public:
//Variable
// Constructors
//- Construct from Istream
nasaHeatCapacityPolynomial(Istream&);
//- Construct from dictionary
nasaHeatCapacityPolynomial(const dictionary& dict);
//- Construct as named copy
inline nasaHeatCapacityPolynomial(const word&, const nasaHeatCapacityPolynomial&);
//- Construct and return a clone
inline autoPtr<nasaHeatCapacityPolynomial> clone() const;
//- Selector from Istream
inline static autoPtr<nasaHeatCapacityPolynomial> New(Istream& is);
// Member Functions
//- perfect Gas Enthalpy [J/kmol]
inline scalar h0(const scalar T) const;
//- perfect Gas Entropy [J/(kmol K)]
inline scalar s0(const scalar T) const;
//- perfect Gas internal Energy [J/kmol]
inline scalar e0(const scalar T) const;
//- perfect gas Heat capacity at constant pressure [J/(kmol K)]
inline scalar cv0(const scalar T) const;
//- perfect gas Heat capacity at constant pressure [J/(kmol K)]
inline scalar cp0(const scalar T) const;
//- Limited Heat capacity at constant pressure [J/(kmol K)]
inline scalar cp(const scalar rho, const scalar T) const;
//- non Limited Heat capacity at constant pressure [J/(kmol K)]
inline scalar cp_nonLimited(const scalar rho, const scalar T) const;
//- Heat capacity at constant pressure [J/(kmol K)]
inline scalar cv(const scalar rho, const scalar T) const;
//- Enthalpy [J/kmol]
inline scalar h(const scalar rho, const scalar T) const;
//- Entropy [J/(kmol K)]
inline scalar s(const scalar rho,const scalar T) const;
//- Internal Energy [J/kmol]
inline scalar e(const scalar rho, const scalar T) const;
// Member operators
inline void operator+=(const nasaHeatCapacityPolynomial&);
inline void operator-=(const nasaHeatCapacityPolynomial&);
// Friend operators
friend nasaHeatCapacityPolynomial operator+ <equationOfState>
(
const nasaHeatCapacityPolynomial&,
const nasaHeatCapacityPolynomial&
);
friend nasaHeatCapacityPolynomial operator- <equationOfState>
(
const nasaHeatCapacityPolynomial&,
const nasaHeatCapacityPolynomial&
);
friend nasaHeatCapacityPolynomial operator* <equationOfState>
(
const scalar,
const nasaHeatCapacityPolynomial&
);
friend nasaHeatCapacityPolynomial operator== <equationOfState>
(
const nasaHeatCapacityPolynomial&,
const nasaHeatCapacityPolynomial&
);
// IOstream Operators
friend Ostream& operator<< <equationOfState>
(
Ostream&,
const nasaHeatCapacityPolynomial&
);
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#include "nasaHeatCapacityPolynomialI.H"
#ifdef NoRepository
# include "nasaHeatCapacityPolynomial.C"
#endif
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View file

@ -0,0 +1,499 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd |
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM; if not, write to the Free Software Foundation,
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Author
Christian Lucas
Institut für Thermodynamik
Technische Universität Braunschweig
Germany
\*---------------------------------------------------------------------------*/
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
//- Construct from components
//CL: used for the operator+
template<class equationOfState>
inline Foam::nasaHeatCapacityPolynomial<equationOfState>::nasaHeatCapacityPolynomial
(
const equationOfState& st,
const scalar a1,
const scalar a2,
const scalar a3,
const scalar a4,
const scalar a5,
const scalar a6,
const scalar a7
)
:
equationOfState(st),
a1_(a1),
a2_(a2),
a3_(a3),
a4_(a4),
a5_(a5),
a6_(a6),
a7_(a7),
e0_std(e0(this->Tstd())),
s0_std(s0(this->Tstd())),
integral_p_dv_std(this->integral_p_dv(this->rhostd(),this->Tstd())),
integral_dpdT_dv_std(this->integral_dpdT_dv(this->rhostd(),this->Tstd())),
cp_std(this->cp_nonLimited(this->rhostd(),this->Tstd()))
{}
//- Construct from components
//CL: used for the operator*
template<class equationOfState>
inline Foam::nasaHeatCapacityPolynomial<equationOfState>::nasaHeatCapacityPolynomial
(
const equationOfState& st,
const scalar a1,
const scalar a2,
const scalar a3,
const scalar a4,
const scalar a5,
const scalar a6,
const scalar a7,
const scalar e0_std_,
const scalar s0_std_,
const scalar integral_p_dv_std_,
const scalar integral_dpdT_dv_std_,
const scalar cp_std_
)
:
equationOfState(st),
a1_(a1),
a2_(a2),
a3_(a3),
a4_(a4),
a5_(a5),
a6_(a6),
a7_(a7),
e0_std(e0_std_),
s0_std(s0_std_),
integral_p_dv_std(integral_p_dv_std_),
integral_dpdT_dv_std(integral_dpdT_dv_std_),
cp_std(cp_std_)
{}
template<class equationOfState>
inline Foam::nasaHeatCapacityPolynomial<equationOfState>::nasaHeatCapacityPolynomial
(
const word& name,
const nasaHeatCapacityPolynomial& np
)
:
equationOfState(name, np),
a1_(np.a1_),
a2_(np.a2_),
a3_(np.a3_),
a4_(np.a4_),
a5_(np.a5_),
a6_(np.a6_),
a7_(np.a7_),
e0_std(np.e0_std),
s0_std(np.s0_std),
integral_p_dv_std(np.integral_p_dv_std),
integral_dpdT_dv_std(np.integral_dpdT_dv_std),
cp_std(np.cp_std)
{}
template<class equationOfState>
inline Foam::autoPtr<Foam::nasaHeatCapacityPolynomial<equationOfState> >
Foam::nasaHeatCapacityPolynomial<equationOfState>::clone() const
{
return autoPtr<nasaHeatCapacityPolynomial<equationOfState> >
(
new nasaHeatCapacityPolynomial<equationOfState>(*this)
);
}
template<class equationOfState>
inline Foam::autoPtr<Foam::nasaHeatCapacityPolynomial<equationOfState> >
Foam::nasaHeatCapacityPolynomial<equationOfState>::New(Istream& is)
{
return autoPtr<nasaHeatCapacityPolynomial<equationOfState> >
(
new nasaHeatCapacityPolynomial<equationOfState>(is)
);
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
//used to calculate the internal energy
//perfect gas enthalpy
template<class equationOfState>
inline Foam::scalar Foam::nasaHeatCapacityPolynomial<equationOfState>::h0
(
const scalar T
) const
{
return
this->RR()*T*
(
-this->a1_*pow(T,-2)
+this->a2_*log(T)/T
+this->a3_
+0.5*this->a4_*T
+(this->a5_*pow(T,2))/3
+(this->a6_*pow(T,3))/4
+(this->a7_*pow(T,4))/5
);
}
//used to calculate the internal energy
//perfect gas internal energy
template<class equationOfState>
inline Foam::scalar Foam::nasaHeatCapacityPolynomial<equationOfState>::e0
(
const scalar T
) const
{
return this->h0(T) - this->RR()*T;
}
// used to calculate the entropy
// perfect gas entropy
template<class equationOfState>
inline Foam::scalar Foam::nasaHeatCapacityPolynomial<equationOfState>::s0
(
const scalar T
) const
{
return this->RR()*
(
this->a1_*(-1)/(2*pow(T,2))
-this->a2_/T+this->a3_*log(T)
+this->a4_*T
+(this->a5_*pow(T,2))/2
+(this->a6_*pow(T,3))/3
+(this->a7_*pow(T,4))/4
);
}
//perfect gas cp
template<class equationOfState>
inline Foam::scalar Foam::nasaHeatCapacityPolynomial<equationOfState>::cp0
(
const scalar T
) const
{
return this->RR()*
(
this->a1_*1/pow(T,2)
+this->a2_*1/T
+this->a3_
+this->a4_*T
+this->a5_*pow(T,2)
+this->a6_*pow(T,3)
+this->a7_*pow(T,4)
);
}
//perfect gas cv
template<class equationOfState>
inline Foam::scalar Foam::nasaHeatCapacityPolynomial<equationOfState>::cv0
(
const scalar T
) const
{
return this->cp0(T)-this->RR();
}
//function to calculate real gas cp
//using cp=cv+(dp/dT)^2/(dp/dv)
template<class equationOfState>
inline Foam::scalar Foam::nasaHeatCapacityPolynomial<equationOfState>::cp
(
const scalar rho,
const scalar T
) const
{
// Problem --> dpdv(rho,T) is =0 at some points within the vapour dome. To increase stability, (dp/dv) has to be limited
// cp can be negative within the vapor dome. To avoid this nonphysical result, the absolute value is used.
// within the vapourdome and at the critical point, cp increases to very high values --> infinity,
// this would decrease the stability, so cp will be limited to 20 times the cp @ STD
return
min
(
cp_std*20,
fabs
(
this->cv(rho,T)
-T*pow((this->dpdT(rho, T)),2)
/min(this->dpdv(rho, T),-1)
)
);
}
// this function is needed to get cp @ STD (without the limit imposed in the function above),
// which in turn is needed to limit the cp in the function above
template<class equationOfState>
inline Foam::scalar Foam::nasaHeatCapacityPolynomial<equationOfState>::cp_nonLimited
(
const scalar rho,
const scalar T
) const
{
return fabs(this->cv(rho,T)-T*pow((this->dpdT(rho, T)),2)/min(this->dpdv(rho, T),-1));
}
//function to calculate real gas cv
//cv=cv0+T*integral d2p/dT2 dv
template<class equationOfState>
inline Foam::scalar Foam::nasaHeatCapacityPolynomial<equationOfState>::cv
(
const scalar rho,
const scalar T
) const
{
return this->cv0(T)+T*this->integral_d2pdT2_dv(rho, T);
}
//function to calculate real gas enthalpy
template<class equationOfState>
inline Foam::scalar Foam::nasaHeatCapacityPolynomial<equationOfState>::h
(
const scalar rho,
const scalar T
) const
{
return this->e(rho,T)+this->p(rho,T)/rho*this->W()-this->Pstd()/this->rhostd()*this->W();
}
// function to calculate real gas internal energy
// important assumption used: internal Energie is 0 at STD conditions.
// equation: du= cv0 dT +[T*dp/dT -p]dv
template<class equationOfState>
inline Foam::scalar Foam::nasaHeatCapacityPolynomial<equationOfState>::e
(
const scalar rho,
const scalar T
) const
{
return
(
-this->Tstd()*integral_dpdT_dv_std
+integral_p_dv_std
+this->e0(T)-e0_std
+T*this->integral_dpdT_dv(rho,T)
-this->integral_p_dv(rho,T)
);
}
//function to calculate real gas entropy
// important assumption used: the Entropy is 0 at STD conditions.
// equation: ds= cv0/T * dT + dp/dT *dv
// --> integral cv0/T dT = s0(T) -s0(Tstd) - R*ln(T/Tstd) --> due to s0(T)-s0(Tstd)=integral cp0/T dT
template<class equationOfState>
inline Foam::scalar Foam::nasaHeatCapacityPolynomial<equationOfState>::s
(
const scalar rho,
const scalar T
) const
{
return -integral_dpdT_dv_std
+(this->s0(T)-s0_std)
-this->RR()*log(T/this->Tstd())
+ this->integral_dpdT_dv(rho,T);
}
// * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * //
template<class equationOfState>
inline void Foam::nasaHeatCapacityPolynomial<equationOfState>::operator+=
(
const nasaHeatCapacityPolynomial<equationOfState>& np
)
{
scalar molr1 = this->nMoles();
equationOfState::operator+=(np);
molr1 /= this->nMoles();
scalar molr2 = np.nMoles()/this->nMoles();
a1_ = molr1*a1_ + molr2*np.a1_;
a2_ = molr1*a2_ + molr2*np.a2_;
a3_ = molr1*a3_ + molr2*np.a3_;
a4_ = molr1*a4_ + molr2*np.a4_;
a5_ = molr1*a5_ + molr2*np.a5_;
a6_ = molr1*a6_ + molr2*np.a6_;
a7_ = molr1*a7_ + molr2*np.a7_;
}
template<class equationOfState>
inline void Foam::nasaHeatCapacityPolynomial<equationOfState>::operator-=
(
const nasaHeatCapacityPolynomial<equationOfState>& np
)
{
scalar molr1 = this->nMoles();
nasaHeatCapacityPolynomial::operator-=(np);
molr1 /= this->nMoles();
scalar molr2 = np.nMoles()/this->nMoles();
a1_ = molr1*a1_ - molr2*np.a1_;
a2_ = molr1*a2_ - molr2*np.a2_;
a3_ = molr1*a3_ - molr2*np.a3_;
a4_ = molr1*a4_ - molr2*np.a4_;
a5_ = molr1*a5_ - molr2*np.a5_;
a6_ = molr1*a6_ - molr2*np.a6_;
a7_ = molr1*a7_ - molr2*np.a7_;
}
// * * * * * * * * * * * * * * * Friend Operators * * * * * * * * * * * * * //
template<class equationOfState>
inline Foam::nasaHeatCapacityPolynomial<equationOfState> Foam::operator+
(
const nasaHeatCapacityPolynomial<equationOfState>& np1,
const nasaHeatCapacityPolynomial<equationOfState>& np2
)
{
equationOfState eofs
(
static_cast<const equationOfState&>(np1)
+ static_cast<const equationOfState&>(np2)
);
//CL: Important, calls a different constructor as operator*
//CL: the coefficients as well as the EOS (coefficients) changed
//CL: therefore, the values at STD needs to be recalculated
return nasaHeatCapacityPolynomial<equationOfState>
(
eofs,
np1.nMoles()/eofs.nMoles()*np1.a1_
+ np2.nMoles()/eofs.nMoles()*np2.a1_,
np1.nMoles()/eofs.nMoles()*np1.a2_
+ np2.nMoles()/eofs.nMoles()*np2.a2_,
np1.nMoles()/eofs.nMoles()*np1.a3_
+ np2.nMoles()/eofs.nMoles()*np2.a3_,
np1.nMoles()/eofs.nMoles()*np1.a4_
+ np2.nMoles()/eofs.nMoles()*np2.a4_,
np1.nMoles()/eofs.nMoles()*np1.a5_
+ np2.nMoles()/eofs.nMoles()*np2.a5_,
np1.nMoles()/eofs.nMoles()*np1.a6_
+ np2.nMoles()/eofs.nMoles()*np2.a6_,
np1.nMoles()/eofs.nMoles()*np1.a7_
+ np2.nMoles()/eofs.nMoles()*np2.a7_
);
}
template<class equationOfState>
inline Foam::nasaHeatCapacityPolynomial<equationOfState> Foam::operator-
(
const nasaHeatCapacityPolynomial<equationOfState>& np1,
const nasaHeatCapacityPolynomial<equationOfState>& np2
)
{
equationOfState eofs
(
static_cast<const equationOfState&>(np1)
- static_cast<const equationOfState&>(np2)
);
return nasaHeatCapacityPolynomial<equationOfState>
(
eofs,
np1.nMoles()/eofs.nMoles()*np1.a1_
- np2.nMoles()/eofs.nMoles()*np2.a1_,
np1.nMoles()/eofs.nMoles()*np1.a2_
- np2.nMoles()/eofs.nMoles()*np2.a2_,
np1.nMoles()/eofs.nMoles()*np1.a3_
- np2.nMoles()/eofs.nMoles()*np2.a3_,
np1.nMoles()/eofs.nMoles()*np1.a4_
- np2.nMoles()/eofs.nMoles()*np2.a4_,
np1.nMoles()/eofs.nMoles()*np1.a5_
- np2.nMoles()/eofs.nMoles()*np2.a5_,
np1.nMoles()/eofs.nMoles()*np1.a6_
- np2.nMoles()/eofs.nMoles()*np2.a6_,
np1.nMoles()/eofs.nMoles()*np1.a7_
- np2.nMoles()/eofs.nMoles()*np2.a7_
);
}
template<class equationOfState>
inline Foam::nasaHeatCapacityPolynomial<equationOfState> Foam::operator*
(
const scalar s,
const nasaHeatCapacityPolynomial<equationOfState>& np
)
{
//CL: values at STD don't need to be recalculated,
//CL: therefore, providing the values in the constructor
return nasaHeatCapacityPolynomial<equationOfState>
(
s*static_cast<const equationOfState&>(np),
np.a1_,
np.a2_,
np.a3_,
np.a4_,
np.a5_,
np.a6_,
np.a7_,
np.e0_std,
np.s0_std,
np.integral_p_dv_std,
np.integral_dpdT_dv_std,
np.cp_std
);
}
template<class equationOfState>
inline Foam::nasaHeatCapacityPolynomial<equationOfState> Foam::operator==
(
const nasaHeatCapacityPolynomial<equationOfState>& np1,
const nasaHeatCapacityPolynomial<equationOfState>& np2
)
{
return np2 - np1;
}
// ************************************************************************* //

View file

@ -0,0 +1,77 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd |
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM; if not, write to the Free Software Foundation,
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Author
Christian Lucas
Institut für Thermodynamik
Technische Universität Braunschweig
Germany
\*---------------------------------------------------------------------------*/
#include "realGasSpecieThermo.H"
#include "IOstreams.H"
/* * * * * * * * * * * * * * * Private Static Data * * * * * * * * * * * * * */
template<class thermo>
const Foam::debug::tolerancesSwitch
Foam::realGasSpecieThermo<thermo>::tol_
(
"realGasSpecieThermoTol",
1.0e-9
);
template<class thermo>
const Foam::debug::optimisationSwitch
Foam::realGasSpecieThermo<thermo>::maxIter_
(
"realGasSpecieThermoMaxIter",
500
);
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
template<class thermo>
Foam::realGasSpecieThermo<thermo>::realGasSpecieThermo(Istream& is)
:
thermo(is)
{
is.check("realGasSpecieThermo::realGasSpecieThermo(Istream& is)");
}
// * * * * * * * * * * * * * * * Ostream Operator * * * * * * * * * * * * * //
template<class thermo>
Foam::Ostream& Foam::operator<<(Ostream& os, const realGasSpecieThermo<thermo>& st)
{
os << static_cast<const thermo&>(st);
os.check("Ostream& operator<<(Ostream& os, const realGasSpecieThermo& st)");
return os;
}
// ************************************************************************* //

View file

@ -0,0 +1,282 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd |
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM; if not, write to the Free Software Foundation,
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Class
Foam::realGasSpecieThermo
Description
This is an subversion of the specieThermo function. While the "orginal" specieThermo function
is only valid for perfect Gases, this function is valid for real gases.
Basic thermodynamics type based on the use of fitting functions for
cp, h, s obtained from the template argument type thermo. All other
properties are derived from these primitive functions.
SourceFiles
realGasSpecieThermoI.H
realGasSpecieThermo.C
Author
Christian Lucas
Institut für Thermodynamik
Technische Universität Braunschweig
Germany
\*---------------------------------------------------------------------------*/
#ifndef realGasSpecieThermo_H
#define realGasSpecieThermo_H
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
// Forward declaration of friend functions and operators
template<class thermo> class realGasSpecieThermo;
template<class thermo>
inline realGasSpecieThermo<thermo> operator+
(
const realGasSpecieThermo<thermo>&,
const realGasSpecieThermo<thermo>&
);
template<class thermo>
inline realGasSpecieThermo<thermo> operator-
(
const realGasSpecieThermo<thermo>&,
const realGasSpecieThermo<thermo>&
);
template<class thermo>
inline realGasSpecieThermo<thermo> operator*
(
const scalar,
const realGasSpecieThermo<thermo>&
);
template<class thermo>
inline realGasSpecieThermo<thermo> operator==
(
const realGasSpecieThermo<thermo>&,
const realGasSpecieThermo<thermo>&
);
template<class thermo>
Ostream& operator<<
(
Ostream&,
const realGasSpecieThermo<thermo>&
);
/*---------------------------------------------------------------------------*\
Class realGasSpecieThermo Declaration
\*---------------------------------------------------------------------------*/
template<class thermo>
class realGasSpecieThermo
:
public thermo
{
// Private data
//- Convergence tolerance of energy -> temperature inversion functions
static const debug::tolerancesSwitch tol_;
//- Max number of iterations in energy->temperature inversion functions
static const debug::optimisationSwitch maxIter_;
// Private member functions
// return the temperature corresponding to the value of the
// thermodynamic property f, given the function f = F(rho,T) and dF(rho,T)/dT
inline void T
(
scalar f,
scalar &T0,
scalar p,
scalar &rho0,
scalar (realGasSpecieThermo::*F)(const scalar,const scalar) const,
scalar (realGasSpecieThermo::*dFdT)(const scalar,const scalar) const
) const;
public:
// Constructors
//- construct from components
inline realGasSpecieThermo(const thermo& sp);
//- Construct from Istream
realGasSpecieThermo(Istream&);
//- Construct as named copy
inline realGasSpecieThermo(const word& name, const realGasSpecieThermo&);
// Member Functions
// Fundamaental properties
// (These functions must be provided in derived types)
// Sensible enthalpy [J/kmol]
//virtual scalar hs(const scalar) const;
// Chemical enthalpy [J/kmol]
//virtual scalar hc(const scalar) const;
// Calculate and return derived properties
// (These functions need not provided in derived types)
//CL: isentropic expansion factor "gamma" (heat capacity ratio for perfect gas)
inline scalar gamma(const scalar T, const scalar rho) const;
//- Sensible internal energy [J/kmol]
// inline scalar es(const scalar p, const scalar rho) const;
//- Gibbs free energy [J/kmol]
inline scalar g(const scalar rho, const scalar T ) const;
//- Helmholtz free energy [J/kmol]
inline scalar a(const scalar rho, const scalar T ) const;
// Mass specific properties
//- Heat capacity at constant pressure [J/(kg K)]
inline scalar Cp(const scalar rho, const scalar T) const;
//- Heat capacity at constant volume [J/(kg K)]
inline scalar Cv(const scalar rho, const scalar T) const;
//- Enthalpy [J/kg]
inline scalar H(const scalar rho, const scalar T) const;
//- Sensible enthalpy [J/kg]
// inline scalar Hs(const scalar T) const;
//- Chemical enthalpy [J/kg]
// inline scalar Hc() const;
//- Entropy [J/(kg K)]
inline scalar S(const scalar rho, const scalar T) const;
//- Internal energy [J/kg]
inline scalar E(const scalar rho, const scalar T) const;
//- Gibbs free energy [J/kg]
inline scalar G(const scalar rho, const scalar T) const;
//- Helmholtz free energy [J/kg]
inline scalar A(const scalar rho, const scalar T) const;
//CL: Other variables
//- Return compressibility drho/dp at h=constant [s^2/m^2]
inline scalar psiH(const scalar rho, const scalar T) const;
//- Return compressibility drho/dp at e=constant [s^2/m^2]
inline scalar psiE(const scalar rho, const scalar T) const;
//- Return compressibility drho/dH at p=constant
inline scalar drhodH(const scalar rho, const scalar T) const;
//- Return compressibility drho/dE at p=constant
inline scalar drhodE(const scalar rho, const scalar T) const;
// Energy->temperature inversion functions
//- Temperature from Enthalpy given an initial temperature T0
inline void TH(const scalar H, scalar &T0,const scalar p, scalar &psi0) const;
//- Temperature from internal energy given an initial temperature T0
inline void TE(const scalar E, scalar &T0,const scalar p, scalar &psi0) const;
// Member operators
inline void operator+=(const realGasSpecieThermo&);
inline void operator-=(const realGasSpecieThermo&);
inline void operator*=(const scalar);
// Friend operators
friend realGasSpecieThermo operator+ <thermo>
(
const realGasSpecieThermo&,
const realGasSpecieThermo&
);
friend realGasSpecieThermo operator- <thermo>
(
const realGasSpecieThermo&,
const realGasSpecieThermo&
);
friend realGasSpecieThermo operator* <thermo>
(
const scalar s,
const realGasSpecieThermo&
);
friend realGasSpecieThermo operator== <thermo>
(
const realGasSpecieThermo&,
const realGasSpecieThermo&
);
// Ostream Operator
friend Ostream& operator<< <thermo>
(
Ostream&,
const realGasSpecieThermo&
);
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#include "realGasSpecieThermoI.H"
#ifdef NoRepository
# include "realGasSpecieThermo.C"
#endif
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View file

@ -0,0 +1,384 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd |
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM; if not, write to the Free Software Foundation,
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Author
Christian Lucas
Institut für Thermodynamik
Technische Universität Braunschweig
Germany
\*---------------------------------------------------------------------------*/
#include "realGasSpecieThermo.H"
template<class thermo>
inline Foam::realGasSpecieThermo<thermo>::realGasSpecieThermo
(
const thermo& sp
)
:
thermo(sp)
{}
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
//CL: using two one dimensional newton solvers in a row
template<class thermo>
inline void Foam::realGasSpecieThermo<thermo>::T
(
scalar f,
scalar &T0,
scalar p,
scalar &rho0,
scalar (realGasSpecieThermo<thermo>::*F)(const scalar,const scalar) const,
scalar (realGasSpecieThermo<thermo>::*dFdT)(const scalar,const scalar) const
) const
{
scalar Test ;
scalar Tnew = T0;
scalar rhoOld;
scalar rho = rho0;
scalar Ttol = T0*tol_();
scalar rhotol = rho0*tol_();
label iter = 0;
label i;
do
{
Test = Tnew;
rhoOld = rho;
rho = this->rho(p, Test, rhoOld);
i = 0;
do
{
//CL: using a stabilizing newton solver
//CL: if the solve is diverging, the step is reduced until the solver converges
Tnew = Test - ((this->*F)(rho, Test) - f)/(this->*dFdT)(rho, Test)/(pow(2, i));
i++;
} while
(
(i<20)
&&
(
mag((this->*F)(rho, Tnew) - f)
>
mag((this->*F)(rho, Test) - f)
)
);
if (iter++ > maxIter_)
{
FatalErrorIn
(
"realGasSpecieThermo<thermo>::T(scalar f, scalar T0, scalar p, scalar rho0, "
"scalar (realGasSpecieThermo<thermo>::*F)(const scalar) const, "
"scalar (realGasSpecieThermo<thermo>::*dFdT)(const scalar) const"
") const"
) << "Maximum number of iterations exceeded"
<< abort(FatalError);
}
} while
//CL: both fields must converge
(
(mag(mag(Tnew) - mag(Test)) > Ttol)
||
(mag(mag(rho) - mag(rhoOld)) > rhotol)
);
rho0=rho;
T0=Tnew;
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
template<class thermo>
inline Foam::realGasSpecieThermo<thermo>::realGasSpecieThermo
(
const word& name,
const realGasSpecieThermo& st
)
:
thermo(name, st)
{}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
template<class thermo>
inline Foam::scalar Foam::realGasSpecieThermo<thermo>::gamma(const scalar rho, const scalar T ) const
{
return -1/(rho*this->p(rho,T))*this->cp(rho,T)/this->cv(rho,T)*this->dpdv(rho,T);
}
template<class thermo>
inline Foam::scalar Foam::realGasSpecieThermo<thermo>::g(const scalar rho, const scalar T ) const
{
return this->h(rho, T) - T*this->s(rho, T);
}
template<class thermo>
inline Foam::scalar Foam::realGasSpecieThermo<thermo>::a(const scalar rho, const scalar T ) const
{
return this->e(rho,T ) - T*this->s(rho, T);
}
template<class thermo>
inline Foam::scalar Foam::realGasSpecieThermo<thermo>::Cp( const scalar rho, const scalar T) const
{
return this->cp(rho, T)/this->W();
}
template<class thermo>
inline Foam::scalar Foam::realGasSpecieThermo<thermo>::Cv( const scalar rho, const scalar T) const
{
return this->cv(rho, T)/this->W();
}
template<class thermo>
inline Foam::scalar Foam::realGasSpecieThermo<thermo>::H(const scalar rho, const scalar T) const
{
return this->h(rho, T)/this->W();
}
template<class thermo>
inline Foam::scalar Foam::realGasSpecieThermo<thermo>::S(const scalar rho, const scalar T) const
{
return this->s(rho, T)/this->W();
}
template<class thermo>
inline Foam::scalar Foam::realGasSpecieThermo<thermo>::E(const scalar rho, const scalar T) const
{
return this->e(rho, T)/this->W();
}
template<class thermo>
inline Foam::scalar Foam::realGasSpecieThermo<thermo>::G(const scalar rho, const scalar T) const
{
return this->g(rho, T)/this->W();
}
template<class thermo>
inline Foam::scalar Foam::realGasSpecieThermo<thermo>::A(const scalar rho, const scalar T) const
{
return this->a(rho, T)/this->W();
}
//CL:- Return compressibility drho/dp at h=constant [s^2/m^2]
//CL:- using Bridgeman's Table
template<class thermo>
inline Foam::scalar Foam::realGasSpecieThermo<thermo>::psiH
(
const scalar rho,
const scalar T
) const
{
scalar beta=this->isobarExpCoef(rho,T);
return
-(
(T*beta*beta-beta)/this->Cp(rho,T)
-this->isothermalCompressiblity(rho,T)*rho
);
}
//CL:- Return compressibility drho/dp at e=constant [s^2/m^2]
//CL:- using Bridgeman's Table
template<class thermo>
inline Foam::scalar Foam::realGasSpecieThermo<thermo>::psiE
(
const scalar rho,
const scalar T
) const
{
scalar V = 1/rho;
scalar cp=this->Cp(rho,T);
scalar beta=this->isobarExpCoef(rho,T);
return
-(
(
T*pow(beta,2)*V
-this->isothermalCompressiblity(rho,T)*cp
)
/
(
cp*V
-beta*this->p(rho,T)*pow(V,2)
)
);
}
//CL:- Returns drho/dH at p=constant
//CL:- using Bridgeman's Table
template<class thermo>
inline Foam::scalar Foam::realGasSpecieThermo<thermo>::drhodH
(
const scalar rho,
const scalar T
) const
{
return -(rho*this->isobarExpCoef(rho,T))/this->Cp(rho,T);
}
//CL:- Returns drho/dE at p=constant
//CL:- using Bridgeman's Table
template<class thermo>
inline Foam::scalar Foam::realGasSpecieThermo<thermo>::drhodE
(
const scalar rho,
const scalar T
) const
{
scalar beta=this->isobarExpCoef(rho,T);
return -(rho*beta)/(this->Cp(rho,T)-beta*this->p(rho,T)/rho);
}
template<class thermo>
inline void Foam::realGasSpecieThermo<thermo>::TH
(
const scalar h,
scalar &T0,
const scalar p,
scalar &rho0
) const
{
T(h, T0, p,rho0, &realGasSpecieThermo<thermo>::H, &realGasSpecieThermo<thermo>::Cp);
}
template<class thermo>
inline void Foam::realGasSpecieThermo<thermo>::TE
(
const scalar e,
scalar &T0,
const scalar p,
scalar &rho0
) const
{
T(e, T0, p,rho0, &realGasSpecieThermo<thermo>::E, &realGasSpecieThermo<thermo>::Cv);
}
// * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * //
template<class thermo>
inline void Foam::realGasSpecieThermo<thermo>::operator+=
(
const realGasSpecieThermo<thermo>& st
)
{
thermo::operator+=(st);
}
template<class thermo>
inline void Foam::realGasSpecieThermo<thermo>::operator-=
(
const realGasSpecieThermo<thermo>& st
)
{
thermo::operator-=(st);
}
template<class thermo>
inline void Foam::realGasSpecieThermo<thermo>::operator*=(const scalar s)
{
thermo::operator*=(s);
}
// * * * * * * * * * * * * * * * Friend Operators * * * * * * * * * * * * * //
template<class thermo>
inline Foam::realGasSpecieThermo<thermo> Foam::operator+
(
const realGasSpecieThermo<thermo>& st1,
const realGasSpecieThermo<thermo>& st2
)
{
return realGasSpecieThermo<thermo>
(
static_cast<const thermo&>(st1) + static_cast<const thermo&>(st2)
);
}
template<class thermo>
inline Foam::realGasSpecieThermo<thermo> Foam::operator-
(
const realGasSpecieThermo<thermo>& st1,
const realGasSpecieThermo<thermo>& st2
)
{
return realGasSpecieThermo<thermo>
(
static_cast<const thermo&>(st1) - static_cast<const thermo&>(st2)
);
}
template<class thermo>
inline Foam::realGasSpecieThermo<thermo> Foam::operator*
(
const scalar s,
const realGasSpecieThermo<thermo>& st
)
{
return realGasSpecieThermo<thermo>
(
s*static_cast<const thermo&>(st)
);
}
template<class thermo>
inline Foam::realGasSpecieThermo<thermo> Foam::operator==
(
const realGasSpecieThermo<thermo>& st1,
const realGasSpecieThermo<thermo>& st2
)
{
return st2 - st1;
}
// ************************************************************************* //

View file

@ -137,6 +137,12 @@ public:
//- Thermal diffusivity for enthalpy [kg/ms]
inline scalar alpha(const scalar T) const;
//- Thermal conductivity [W/mK] for real gas
inline scalar kappa(const scalar rho, const scalar T) const;
//- Thermal diffusivity for enthalpy [kg/ms] for real gas
inline scalar alpha(const scalar rho, const scalar T) const;
// Species diffusivity
//inline scalar D(const scalar T) const;

View file

@ -116,7 +116,34 @@ inline scalar constTransport<thermo>::alpha(const scalar T) const
return Cp_*mu(T)*rPr/CpBar;
}
// CL: for real gas thermo
// Thermal conductivity [W/mK]
template<class thermo>
inline scalar constTransport<thermo>::kappa(const scalar rho, const scalar T) const
{
return this->Cp(rho, T)*mu(T)*rPr;
}
// CL: for real gas thermo
// Thermal diffusivity for enthalpy [kg/ms]
template<class thermo>
inline scalar constTransport<thermo>::alpha
(
const scalar rho,
const scalar T
) const
{
scalar Cp_ = this->Cp(rho, T);
scalar deltaT = T - specie::Tstd();
scalar CpBar =
(
deltaT*(this->H(rho, T) - this->H(this->rhostd(), specie::Tstd()))
+ Cp_
)/(sqr(deltaT) + 1);
return Cp_*mu(T)*rPr/CpBar;
}
// * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * //
template<class thermo>

View file

@ -0,0 +1,56 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | foam-extend: Open Source CFD
\\ / O peration |
\\ / A nd | For copyright notice see file Copyright
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of foam-extend.
foam-extend is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation, either version 3 of the License, or (at your
option) any later version.
foam-extend is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with foam-extend. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "constRealGasTransport.H"
#include "IOstreams.H"
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
template<class Thermo>
Foam::constRealGasTransport<Thermo>::constRealGasTransport(Istream& is)
:
Thermo(is),
mu_(readScalar(is)),
rPr_(1.0/readScalar(is))
{
is.check("constRealGasTransport::constRealGasTransport(Istream& is)");
}
// * * * * * * * * * * * * * * * IOstream Operators * * * * * * * * * * * * //
template<class Thermo>
Foam::Ostream& Foam::operator<<(Ostream& os, const constRealGasTransport<Thermo>& ct)
{
operator<<(os, static_cast<const Thermo&>(ct));
os << tab << ct.mu_ << tab << 1.0/ct.rPr_;
os.check("Ostream& operator<<(Ostream&, const constRealGasTransport&)");
return os;
}
// ************************************************************************* //

View file

@ -0,0 +1,202 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | foam-extend: Open Source CFD
\\ / O peration |
\\ / A nd | For copyright notice see file Copyright
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of foam-extend.
foam-extend is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation, either version 3 of the License, or (at your
option) any later version.
foam-extend is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with foam-extend. If not, see <http://www.gnu.org/licenses/>.
Class
Foam::constRealGasTransport
Description
Constant properties Transport package.
Templated into a given thermodynamics package (needed for thermal
conductivity).
SourceFiles
constRealGasTransportI.H
constRealGasTransport.C
\*---------------------------------------------------------------------------*/
#ifndef constRealGasTransport_H
#define constRealGasTransport_H
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
// Forward declaration of friend functions and operators
template<class Thermo> class constRealGasTransport;
template<class Thermo>
inline constRealGasTransport<Thermo> operator+
(
const constRealGasTransport<Thermo>&,
const constRealGasTransport<Thermo>&
);
template<class Thermo>
inline constRealGasTransport<Thermo> operator-
(
const constRealGasTransport<Thermo>&,
const constRealGasTransport<Thermo>&
);
template<class Thermo>
inline constRealGasTransport<Thermo> operator*
(
const scalar,
const constRealGasTransport<Thermo>&
);
template<class Thermo>
inline constRealGasTransport<Thermo> operator==
(
const constRealGasTransport<Thermo>&,
const constRealGasTransport<Thermo>&
);
template<class Thermo>
Ostream& operator<<
(
Ostream&,
const constRealGasTransport<Thermo>&
);
/*---------------------------------------------------------------------------*\
Class constRealGasTransport Declaration
\*---------------------------------------------------------------------------*/
template<class Thermo>
class constRealGasTransport
:
public Thermo
{
// Private data
//- Constant dynamic viscosity [Pa.s]
scalar mu_;
//- Reciprocal Prandtl Number []
scalar rPr_;
// Private Member Functions
//- Construct from components
inline constRealGasTransport
(
const Thermo& t,
const scalar mu,
const scalar Pr
);
public:
// Constructors
//- Construct as named copy
inline constRealGasTransport(const word&, const constRealGasTransport&);
//- Construct from Istream
constRealGasTransport(Istream&);
// Member functions
//- Dynamic viscosity [kg/ms]
inline scalar mu(const scalar T) const;
//- Thermal conductivity [W/mK]
inline scalar kappa(const scalar rho, const scalar T) const;
//- Thermal diffusivity for enthalpy [kg/ms]
inline scalar alpha(const scalar rho, const scalar T) const;
// Species diffusivity
//inline scalar D(const scalar T) const;
// Member operators
inline constRealGasTransport& operator=
(
const constRealGasTransport&
);
// Friend operators
friend constRealGasTransport operator+ <Thermo>
(
const constRealGasTransport&,
const constRealGasTransport&
);
friend constRealGasTransport operator- <Thermo>
(
const constRealGasTransport&,
const constRealGasTransport&
);
friend constRealGasTransport operator* <Thermo>
(
const scalar,
const constRealGasTransport&
);
friend constRealGasTransport operator== <Thermo>
(
const constRealGasTransport&,
const constRealGasTransport&
);
// Ostream Operator
friend Ostream& operator<< <Thermo>
(
Ostream&,
const constRealGasTransport&
);
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#include "constRealGasTransportI.H"
#ifdef NoRepository
# include "constRealGasTransport.C"
#endif
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View file

@ -0,0 +1,217 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | foam-extend: Open Source CFD
\\ / O peration |
\\ / A nd | For copyright notice see file Copyright
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of foam-extend.
foam-extend is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation, either version 3 of the License, or (at your
option) any later version.
foam-extend is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with foam-extend. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
template<class Thermo>
inline Foam::constRealGasTransport<Thermo>::constRealGasTransport
(
const Thermo& t,
const scalar mu,
const scalar Pr
)
:
Thermo(t),
mu_(mu),
rPr_(1.0/Pr)
{}
template<class Thermo>
inline Foam::constRealGasTransport<Thermo>::constRealGasTransport
(
const word& name,
const constRealGasTransport& ct
)
:
Thermo(name, ct),
mu_(ct.mu_),
rPr_(ct.rPr_)
{}
// Construct and return a clone
template<class thermo>
inline autoPtr<constRealGasTransport<Thermo> > constTransport<thermo>::clone
() const
{
return autoPtr<constRealGasTransport<Thermo> >
(
new constTransport<thermo>(*this)
);
}
// Selector from Istream
template<class thermo>
inline autoPtr<constRealGasTransport<Thermo> > constTransport<thermo>::New
(
Istream& is
)
{
return autoPtr<constRealGasTransport<Thermo> >
(
new constRealGasTransport<thermo>(is)
);
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
template<class Thermo>
inline Foam::scalar Foam::constRealGasTransport<Thermo>::mu(const scalar) const
{
return mu_;
}
// CL: for real gas thermo
// Thermal conductivity [W/mK]
template<class thermo>
inline Foam::scalar Foam::constRealGasTransport<thermo>::kappa(const scalar rho, const scalar T) const
{
return this->Cp(rho, T)*mu(T)*rPr_;
}
// CL: for real gas thermo
// Thermal diffusivity for enthalpy [kg/ms]
template<class thermo>
inline Foam::scalar Foam::constRealGasTransport<thermo>::alpha(const scalar rho, const scalar T) const
{
scalar Cp_ = this->Cp(rho, T);
scalar deltaT = T - specie::Tstd();
scalar CpBar =
(deltaT*(this->H(rho, T) - this->H(this->rhostd(), specie::Tstd())) + Cp_)/(sqr(deltaT) + 1);
return Cp_*mu(T)*rPr_/CpBar;
}
// * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * //
template<class Thermo>
inline Foam::constRealGasTransport<Thermo>& Foam::constRealGasTransport<Thermo>::operator=
(
const constRealGasTransport<Thermo>& ct
)
{
Thermo::operator=(ct);
mu_ = ct.mu_;
rPr_ = ct.rPr_;
return *this;
}
// * * * * * * * * * * * * * * * Friend Operators * * * * * * * * * * * * * //
template<class Thermo>
inline Foam::constRealGasTransport<Thermo> Foam::operator+
(
const constRealGasTransport<Thermo>& ct1,
const constRealGasTransport<Thermo>& ct2
)
{
Thermo t
(
static_cast<const Thermo&>(ct1) + static_cast<const Thermo&>(ct2)
);
scalar molr1 = ct1.nMoles()/t.nMoles();
scalar molr2 = ct2.nMoles()/t.nMoles();
return constRealGasTransport<Thermo>
(
t,
molr1*ct1.mu_ + molr2*ct2.mu_,
molr1*ct1.rPr_ + molr2*ct2.rPr_
);
}
template<class Thermo>
inline Foam::constRealGasTransport<Thermo> Foam::operator-
(
const constRealGasTransport<Thermo>& ct1,
const constRealGasTransport<Thermo>& ct2
)
{
Thermo t
(
static_cast<const Thermo&>(ct1) - static_cast<const Thermo&>(ct2)
);
scalar molr1 = ct1.nMoles()/t.nMoles();
scalar molr2 = ct2.nMoles()/t.nMoles();
return constRealGasTransport<Thermo>
(
t,
molr1*ct1.mu_ - molr2*ct2.mu_,
molr1*ct1.rPr_ - molr2*ct2.rPr_
);
}
template<class Thermo>
inline Foam::constRealGasTransport<Thermo> Foam::operator*
(
const scalar s,
const constRealGasTransport<Thermo>& ct
)
{
return constRealGasTransport<Thermo>
(
s*static_cast<const Thermo&>(ct),
ct.mu_,
ct.rPr_
);
}
template<class Thermo>
inline Foam::constRealGasTransport<Thermo> Foam::operator==
(
const constRealGasTransport<Thermo>& ct1,
const constRealGasTransport<Thermo>& ct2
)
{
return ct2 - ct1;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// ************************************************************************* //

View file

@ -159,6 +159,12 @@ public:
//- Thermal diffusivity for enthalpy [kg/ms]
inline scalar alpha(const scalar T) const;
//- Thermal conductivity [W/mK] for real gas
inline scalar kappa(const scalar rho, const scalar T) const;
//- Thermal diffusivity for enthalpy [kg/ms] for real gas
inline scalar alpha(const scalar rho, const scalar T) const;
// Species diffusivity
//inline scalar D(const scalar T) const;

View file

@ -150,7 +150,45 @@ inline scalar sutherlandTransport<thermo>::alpha(const scalar T) const
scalar deltaT = T - specie::Tstd();
scalar CpBar =
(deltaT*(this->H(T) - this->H(specie::Tstd())) + Cp_)/(sqr(deltaT) + 1);
(deltaT*(this->H(T) - this->H(specie::Tstd())) + Cp_)
/(sqr(deltaT) + 1);
return mu(T)*Cv_*(1.32 + 1.77*R_/Cv_)/CpBar;
}
// CL: for real gas thermo
// Thermal conductivity [W/mK]
template<class thermo>
inline scalar sutherlandTransport<thermo>::kappa
(
const scalar rho,
const scalar T
) const
{
scalar Cv_ = this->Cv(rho,T);
return mu(T)*Cv_*(1.32 + 1.77*this->R()/Cv_);
}
// CL: for real gas thermo
// Thermal diffusivity for enthalpy [kg/ms]
template<class thermo>
inline scalar sutherlandTransport<thermo>::alpha
(
const scalar rho,
const scalar T
) const
{
scalar Cv_ = this->Cv(rho, T);
scalar Cp_ = this->Cp(rho, T);
scalar deltaT = T - specie::Tstd();
scalar CpBar =
(
deltaT*(this->H(rho, T) - this->H(this->rhostd(), specie::Tstd()))
+ Cp_
)/(sqr(deltaT) + 1);
return mu(T)*Cv_*(1.32 + 1.77*this->R()/Cv_)/CpBar;
}

View file

@ -14,4 +14,19 @@ $(NSRDSfunctions)/NSRDSfunc7/NSRDSfunc7.C
$(NSRDSfunctions)/NSRDSfunc14/NSRDSfunc14.C
$(APIfunctions)/APIdiffCoefFunc/APIdiffCoefFunc.C
freesteam-2.1/common.c
freesteam-2.1/steam.c
freesteam-2.1/b23.c
freesteam-2.1/backwards.c
freesteam-2.1/viscosity.c
freesteam-2.1/thcond.c
freesteam-2.1/region1.c
freesteam-2.1/region2.c
freesteam-2.1/region3.c
freesteam-2.1/region4.c
freesteam-2.1/steam_pv.c
freesteam-2.1/steam_ph.c
freesteam-2.1/steam_pT.c
freesteam-2.1/zeroin.c
LIB = $(FOAM_LIBBIN)/libthermophysicalFunctions

View file

@ -0,0 +1,43 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?fileVersion 4.0.0?>
<cproject storage_type_id="org.eclipse.cdt.core.XmlProjectDescriptionStorage">
<storageModule moduleId="org.eclipse.cdt.core.settings">
<cconfiguration id="cdt.managedbuild.toolchain.gnu.base.487904684">
<storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="cdt.managedbuild.toolchain.gnu.base.487904684" moduleId="org.eclipse.cdt.core.settings" name="Default">
<externalSettings/>
<extensions>
<extension id="org.eclipse.cdt.core.ELF" point="org.eclipse.cdt.core.BinaryParser"/>
<extension id="org.eclipse.cdt.core.GmakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.CWDLocator" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.GASErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.GLDErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
</extensions>
</storageModule>
<storageModule moduleId="cdtBuildSystem" version="4.0.0">
<configuration buildProperties="" id="cdt.managedbuild.toolchain.gnu.base.487904684" name="Default" parent="org.eclipse.cdt.build.core.emptycfg">
<folderInfo id="cdt.managedbuild.toolchain.gnu.base.487904684.503514498" name="/" resourcePath="">
<toolChain id="cdt.managedbuild.toolchain.gnu.base.1893306594" name="cdt.managedbuild.toolchain.gnu.base" superClass="cdt.managedbuild.toolchain.gnu.base">
<targetPlatform archList="all" binaryParser="org.eclipse.cdt.core.ELF" id="cdt.managedbuild.target.gnu.platform.base.1304117584" name="Debug Platform" osList="linux,hpux,aix,qnx" superClass="cdt.managedbuild.target.gnu.platform.base"/>
<builder id="cdt.managedbuild.target.gnu.builder.base.227643906" managedBuildOn="false" name="Gnu Make Builder.Default" superClass="cdt.managedbuild.target.gnu.builder.base"/>
<tool id="cdt.managedbuild.tool.gnu.archiver.base.475368644" name="GCC Archiver" superClass="cdt.managedbuild.tool.gnu.archiver.base"/>
<tool id="cdt.managedbuild.tool.gnu.cpp.compiler.base.758011200" name="GCC C++ Compiler" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.base"/>
<tool id="cdt.managedbuild.tool.gnu.c.compiler.base.1423750360" name="GCC C Compiler" superClass="cdt.managedbuild.tool.gnu.c.compiler.base"/>
<tool id="cdt.managedbuild.tool.gnu.c.linker.base.1494542762" name="GCC C Linker" superClass="cdt.managedbuild.tool.gnu.c.linker.base"/>
<tool id="cdt.managedbuild.tool.gnu.cpp.linker.base.590138482" name="GCC C++ Linker" superClass="cdt.managedbuild.tool.gnu.cpp.linker.base"/>
<tool id="cdt.managedbuild.tool.gnu.assembler.base.304660451" name="GCC Assembler" superClass="cdt.managedbuild.tool.gnu.assembler.base"/>
</toolChain>
</folderInfo>
</configuration>
</storageModule>
<storageModule moduleId="org.eclipse.cdt.core.externalSettings"/>
</cconfiguration>
</storageModule>
<storageModule moduleId="cdtBuildSystem" version="4.0.0">
<project id="freesteam.null.2007861953" name="freesteam"/>
</storageModule>
<storageModule moduleId="scannerConfiguration">
<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
</storageModule>
</cproject>

View file

@ -0,0 +1,79 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>freesteam</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.cdt.managedbuilder.core.genmakebuilder</name>
<triggers>clean,full,incremental,</triggers>
<arguments>
<dictionary>
<key>?name?</key>
<value></value>
</dictionary>
<dictionary>
<key>org.eclipse.cdt.make.core.append_environment</key>
<value>true</value>
</dictionary>
<dictionary>
<key>org.eclipse.cdt.make.core.autoBuildTarget</key>
<value>all</value>
</dictionary>
<dictionary>
<key>org.eclipse.cdt.make.core.buildArguments</key>
<value></value>
</dictionary>
<dictionary>
<key>org.eclipse.cdt.make.core.buildCommand</key>
<value>make</value>
</dictionary>
<dictionary>
<key>org.eclipse.cdt.make.core.cleanBuildTarget</key>
<value>clean</value>
</dictionary>
<dictionary>
<key>org.eclipse.cdt.make.core.contents</key>
<value>org.eclipse.cdt.make.core.activeConfigSettings</value>
</dictionary>
<dictionary>
<key>org.eclipse.cdt.make.core.enableAutoBuild</key>
<value>false</value>
</dictionary>
<dictionary>
<key>org.eclipse.cdt.make.core.enableCleanBuild</key>
<value>true</value>
</dictionary>
<dictionary>
<key>org.eclipse.cdt.make.core.enableFullBuild</key>
<value>true</value>
</dictionary>
<dictionary>
<key>org.eclipse.cdt.make.core.fullBuildTarget</key>
<value>all</value>
</dictionary>
<dictionary>
<key>org.eclipse.cdt.make.core.stopOnError</key>
<value>true</value>
</dictionary>
<dictionary>
<key>org.eclipse.cdt.make.core.useDefaultBuildCmd</key>
<value>true</value>
</dictionary>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder</name>
<triggers>full,incremental,</triggers>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.cdt.core.cnature</nature>
<nature>org.eclipse.cdt.core.ccnature</nature>
<nature>org.eclipse.cdt.managedbuilder.core.managedBuildNature</nature>
<nature>org.eclipse.cdt.managedbuilder.core.ScannerConfigNature</nature>
</natures>
</projectDescription>

View file

@ -0,0 +1,340 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.

View file

@ -0,0 +1,28 @@
FREESTEAM
=========
Note: We ripped out what we needed, here is the full description!
This is a package for calculating the properties of water and steam
using the IAPWS-IF97 industry-standard steam properties correlations.
freesteam includes a thorough set of test cases; you are encouraged to inspect
these for yourself to assure yourself that freesteam is accurate for the cases
you required.
freesteam is not a stand-alone program in its own right. Rather, it is a 'shared
library' that implements a range of functions that you can use to work out steam
properties in your own program that you write yourself.
This version 2.x release of freesteam is a complete re-write of freesteam in
pure C. We have removed all the complicated C++ template code (excessively
complicated) as well as the units-of-measurement code (cute, but also
rather hard to maintain). This has the immediate advantage that the resulting
DLLs/libraries can be linked to from all C/C++ compilers, something which was
not possible with the previous C++ version.
For more information, see
http://freesteam.sourceforge.net/

View file

@ -0,0 +1,40 @@
/*
freesteam - IAPWS-IF97 steam tables library
Copyright (C) 2004-2005 John Pye
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.*/
#define FREESTEAM_BUILDING_LIB
#include "b23.h"
#include <math.h>
const double B23_N[6] = { 0, 0.34805185628969E+03, -0.11671859879975E+01
, 0.10192970039326E-02, 0.57254459862746E+03, 0.13918839778870E+02
};
const double B23_PSTAR = 1e6;
double freesteam_b23_p_T(double T){
#define theta T
return (B23_N[1] + B23_N[2] * theta + B23_N[3] * SQ(theta)) * B23_PSTAR;
#undef theta
}
double freesteam_b23_T_p(double p){
double pi = p / B23_PSTAR;
return B23_N[4] + sqrt((pi - B23_N[5])/B23_N[3]) /* * 1{K} */;
}

View file

@ -0,0 +1,27 @@
/*
freesteam - IAPWS-IF97 steam tables library
Copyright (C) 2004-2005 John Pye
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.*/
#ifndef FREESTEAM_B23_H
#define FREESTEAM_B23_H
#include "common.h"
FREESTEAM_DLL double freesteam_b23_p_T(double T);
FREESTEAM_DLL double freesteam_b23_T_p(double p);
#endif

View file

@ -0,0 +1,869 @@
/*
freesteam - IAPWS-IF97 steam tables library
Copyright (C) 2004-2009 John Pye
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*//** @file
Backwards equations for IAPWS-IF97. Facilitate calculation of
properties in terms of (p,h) without requiring any iteration.
TODO add boundary curves?
TODO add more equations for (p,s) calculation?
Numerical data for T(p,h) and v(p,h) correlations was extracted from
the Matlab version 2.6 of Xsteam by by Magnus Holmgren.
*/
#define FREESTEAM_BUILDING_LIB
#include "backwards.h"
#include "backwards_impl.h"
#include <math.h>
/*------------------------------------------------------------------------------
REGION 1 BACKWARDS EQUATION T(P,H)
*/
typedef struct{
int I, J;
double n;
} BackwardsData;
/**
Source: IAPWS-IF97-REV section 5.2.1
*/
BackwardsData REGION1_TPH_DATA[] = {
{0, 0, -238.72489924521}
,{0, 1, 404.21188637945}
,{0, 2, 113.49746881718}
,{0, 6, -5.8457616048039}
,{0, 22, -1.528548241314E-04}
,{0, 32, -1.0866707695377E-06}
,{1, 0, -13.391744872602}
,{1, 1, 43.211039183559}
,{1, 2, -54.010067170506}
,{1, 3, 30.535892203916}
,{1, 4, -6.5964749423638}
,{1,10, 9.3965400878363E-03}
,{1,32, 1.157364750534E-07}
,{2,10,-2.5858641282073E-05}
,{2,32,-4.0644363084799E-09}
,{3,10,6.6456186191635E-08}
,{3,32,8.0670734103027E-11}
,{4,32,-9.3477771213947E-13}
,{5,32,5.8265442020601E-15}
,{6,32,-1.5020185953503E-17}
};
const unsigned REGION1_TPH_MAX = sizeof(REGION1_TPH_DATA)/sizeof(BackwardsData);
const double REGION1_TPH_HSTAR = 2500e3; /* J/kg */
const double REGION1_TPH_PSTAR = 1e6; /* Pa */
/**
Backward equation for temperature in terms of pressure and enthalpy
in IAPWS-IF97 Region 1. Source: IAPWS-IF97-Rev section 5.2.1.
@param p pressure in Pa
@param h enthalpy in J/kg
@return temperature in K
*/
double freesteam_region1_T_ph(double p, double h){
double pi = p / REGION1_TPH_PSTAR;
double e1 = 1. + (h / REGION1_TPH_HSTAR);
unsigned i;
BackwardsData *d;
double sum = 0;
for(i=0, d = REGION1_TPH_DATA; i<REGION1_TPH_MAX; ++i, ++d){
/* TODO some optimisations are possible here with pow(pi,...) */
sum += d->n * ipow(pi,d->I) * ipow(e1, d->J);
}
return sum /* * REGION1_TPH_TSTAR = 1. */;
}
/*------------------------------------------------------------------------------
REGION 2 BACKWARDS EQUATION T(P,H)
*/
/* sub-region 2a */
BackwardsData REGION2A_TPH_DATA[] = {
{0, 0, 1089.8952318288}
,{0, 1, 849.51654495535}
,{0, 2, -107.81748091826}
,{0, 3, 33.153654801263}
,{0, 7, -7.4232016790248}
,{0, 20, 11.765048724356}
,{1, 0, 1.844574935579}
,{1, 1, -4.1792700549624}
,{1, 2, 6.2478196935812}
,{1, 3, -17.344563108114}
,{1, 7, -200.58176862096}
,{1, 9, 271.96065473796}
,{1, 11, -455.11318285818}
,{1, 18, 3091.9688604755}
,{1, 44, 252266.40357872}
,{2, 0, -6.1707422868339E-03}
,{2, 2, -0.31078046629583}
,{2, 7, 11.670873077107}
,{2, 36, 128127984.04046}
,{2, 38, -985549096.23276}
,{2, 40, 2822454697.3002}
,{2, 42, -3594897141.0703}
,{2, 44, 1722734991.3197}
,{3, 24, -13551.334240775}
,{3, 44, 12848734.66465}
,{4, 12, 1.3865724283226}
,{4, 32, 235988.32556514}
,{4, 44, -13105236.545054}
,{5, 32, 7399.9835474766}
,{5, 36, -551966.9703006}
,{5, 42, 3715408.5996233}
,{6, 34, 19127.72923966}
,{6, 44, -415351.64835634}
,{7, 28, -62.459855192507}
};
const unsigned REGION2A_TPH_MAX = sizeof(REGION2A_TPH_DATA)/sizeof(BackwardsData);
/* sub-region 2b */
BackwardsData REGION2B_TPH_DATA[] = {
{0, 0, 1489.5041079516}
,{0, 1, 743.07798314034}
,{0, 2, -97.708318797837}
,{0, 12, 2.4742464705674}
,{0, 18, -0.63281320016026}
,{0, 24, 1.1385952129658}
,{0, 28, -0.47811863648625}
,{0, 40, 8.5208123431544E-03}
,{1, 0, 0.93747147377932}
,{1, 2, 3.3593118604916}
,{1, 6, 3.3809355601454}
,{1, 12, 0.16844539671904}
,{1, 18, 0.73875745236695}
,{1, 24, -0.47128737436186}
,{1, 28, 0.15020273139707}
,{1, 40, -0.002176411421975}
,{2, 2, -0.021810755324761}
,{2, 8, -0.10829784403677}
,{2, 18, -0.046333324635812}
,{2, 40, 7.1280351959551E-05}
,{3, 1, 1.1032831789999E-04}
,{3, 2, 1.8955248387902E-04}
,{3, 12, 3.0891541160537E-03}
,{3, 24, 1.3555504554949E-03}
,{4, 2, 2.8640237477456E-07}
,{4, 12, -1.0779857357512E-05}
,{4, 18, -7.6462712454814E-05}
,{4, 24, 1.4052392818316E-05}
,{4, 28, -3.1083814331434E-05}
,{4, 40, -1.0302738212103E-06}
,{5, 18, 2.821728163504E-07}
,{5, 24, 1.2704902271945E-06}
,{5, 40, 7.3803353468292E-08}
,{6, 28, -1.1030139238909E-08}
,{7, 2, -8.1456365207833E-14}
,{7, 28, -2.5180545682962E-11}
,{9, 1, -1.7565233969407E-18}
,{9, 40, 8.6934156344163E-15}
};
const unsigned REGION2B_TPH_MAX = sizeof(REGION2B_TPH_DATA)/sizeof(BackwardsData);
/* sub-region 2c */
BackwardsData REGION2C_TPH_DATA[] ={
{-7, 0, -3236839855524.2}
,{-7, 4, 7326335090218.1}
,{-6, 0, 358250899454.47}
,{-6, 2, -583401318515.9}
,{-5, 0, -10783068217.47}
,{-5, 2, 20825544563.171}
,{-2, 0, 610747.83564516}
,{-2, 1, 859777.2253558}
,{-1, 0, -25745.72360417}
,{-1, 2, 31081.088422714}
,{0, 0, 1208.2315865936}
,{0, 1, 482.19755109255}
,{1, 4, 3.7966001272486}
,{1, 8, -10.842984880077}
,{2, 4, -0.04536417267666}
,{6, 0, 1.4559115658698E-13}
,{6, 1, 1.126159740723E-12}
,{6, 4, -1.7804982240686E-11}
,{6, 10, 1.2324579690832E-07}
,{6, 12, -1.1606921130984E-06}
,{6, 16, 2.7846367088554E-05}
,{6, 20, -5.9270038474176E-04}
,{6, 22, 1.2918582991878E-03}
};
const unsigned REGION2C_TPH_MAX = sizeof(REGION2C_TPH_DATA)/sizeof(BackwardsData);
const double REGION2AB_P = 4.e6; /* Pa */
const double REGION2_HSTAR = 2000e3;
const double REGION2_PSTAR = 1.e6;
/* REGION2_B2BC_PH defined in backwards_impl.h */
/**
Backward equation for temperature in terms of pressure and enthalpy
in IAPWS-IF97 Region 2 (composed of sub-regions 2a, 2b, 2c).
Source: IAPWS-IF97-Rev section 5.2.1.
@param p pressure in Pa
@param h enthalpy in J/kg
@return temperature in K
*/
double freesteam_region2_T_ph(double p, double h){
IAPWS97_APPROXIMATE;
double eta = h / REGION2_HSTAR;
double pi = p / REGION2_PSTAR;
double pi1, eta1;
BackwardsData *d;
unsigned i, n;
double sum = 0;
if(p < REGION2AB_P){
//fprintf(stderr,"region 2a\n");
pi1 = pi; eta1 = eta - 2.1;
d = REGION2A_TPH_DATA;
n = REGION2A_TPH_MAX;
}else{
if(REGION2_B2BC_PH(p,h) < 0.){
//fprintf(stderr,"region 2b\n");
pi1 = pi - 2.; eta1 = eta - 2.6;
d = REGION2B_TPH_DATA;
n = REGION2B_TPH_MAX;
}else{
//fprintf(stderr,"region 2c\n");
pi1 = pi + 25.; eta1 = eta - 1.8;
d = REGION2C_TPH_DATA;
n = REGION2C_TPH_MAX;
}
}
for(i = 0; i<n; ++i, ++d){
sum += d->n * ipow(pi1, d->I) * ipow(eta1, d->J);
}
return sum /* * REGION2_TSTAR = 1 K */;
}
/*------------------------------------------------------------------------------
REGION 3 BACKWARDS EQUATION T(P,H)
*/
/* sub-region 3a */
BackwardsData REGION3A_TPH_DATA[] = {
{-12, 0, -1.33645667811215E-07}
,{-12, 1, 4.55912656802978E-06}
,{-12, 2, -1.46294640700979E-05}
,{-12, 6, 6.3934131297008E-03}
,{-12, 14, 372.783927268847}
,{-12, 16, -7186.54377460447}
,{-12, 20, 573494.7521034}
,{-12, 22, -2675693.29111439}
,{-10, 1, -3.34066283302614E-05}
,{-10, 5, -2.45479214069597E-02}
,{-10, 12, 47.8087847764996}
,{-8, 0, 7.64664131818904E-06}
,{-8, 2, 1.28350627676972E-03}
,{-8, 4, 1.71219081377331E-02}
,{-8, 10, -8.51007304583213}
,{-5, 2, -1.36513461629781E-02}
,{-3, 0, -3.84460997596657E-06}
,{-2, 1, 3.37423807911655E-03}
,{-2, 3, -0.551624873066791}
,{-2, 4, 0.72920227710747}
,{-1, 0, -9.92522757376041E-03}
,{-1, 2, -0.119308831407288}
,{0, 0, 0.793929190615421}
,{0, 1, 0.454270731799386}
,{1, 1, 0.20999859125991}
,{3, 0, -6.42109823904738E-03}
,{3, 1, -0.023515586860454}
,{4, 0, 2.52233108341612E-03}
,{4, 3, -7.64885133368119E-03}
,{10, 4, 1.36176427574291E-02}
,{12, 5, -1.33027883575669E-02}
};
const unsigned REGION3A_TPH_MAX = sizeof(REGION3A_TPH_DATA)/sizeof(BackwardsData);
BackwardsData REGION3B_TPH_DATA[] = {
{-12, 0, 3.2325457364492E-05}
,{-12, 1, -1.27575556587181E-04}
,{-10, 0, -4.75851877356068E-04}
,{-10, 1, 1.56183014181602E-03}
,{-10, 5, 0.105724860113781}
,{-10, 10, -85.8514221132534}
,{-10, 12, 724.140095480911}
,{-8, 0, 2.96475810273257E-03}
,{-8, 1, -5.92721983365988E-03}
,{-8, 2, -1.26305422818666E-02}
,{-8, 4, -0.115716196364853}
,{-8, 10, 84.9000969739595}
,{-6, 0, -1.08602260086615E-02}
,{-6, 1, 1.54304475328851E-02}
,{-6, 2, 7.50455441524466E-02}
,{-4, 0, 2.52520973612982E-02}
,{-4, 1, -6.02507901232996E-02}
,{-3, 5, -3.07622221350501}
,{-2, 0, -5.74011959864879E-02}
,{-2, 4, 5.03471360939849}
,{-1, 2, -0.925081888584834}
,{-1, 4, 3.91733882917546}
,{-1, 6, -77.314600713019}
,{-1, 10, 9493.08762098587}
,{-1, 14, -1410437.19679409}
,{-1, 16, 8491662.30819026}
,{0, 0, 0.861095729446704}
,{0, 2, 0.32334644281172}
,{1, 1, 0.873281936020439}
,{3, 1, -0.436653048526683}
,{5, 1, 0.286596714529479}
,{6, 1, -0.131778331276228}
,{8, 1, 6.76682064330275E-03}
};
const unsigned REGION3B_TPH_MAX = sizeof(REGION3B_TPH_DATA)/sizeof(BackwardsData);
/* REGION3_B3AB_PH(P,H) boundary test declared in backwards_impl.h */
const double REGION3A_TPH_HSTAR = 2300e3;
const double REGION3A_TPH_PSTAR = 100.e6;
const double REGION3A_TPH_TSTAR = 760;
const double REGION3B_TPH_HSTAR = 2800e3;
const double REGION3B_TPH_PSTAR = 100.e6;
const double REGION3B_TPH_TSTAR = 860;
/**
Backward equation for temperature in terms of pressure and enthalpy
in IAPWS-IF97 Region 3 (composed of sub-regions 3a, 3b).
Source: IAPWS 'Revised Supplementary Release on Backward Equations for the Functions
T(p,h), v(p,h) and T(p,s), v(p,s) for Region 3 of the IAPWS Industrial
Formulation 1997 for the Thermodynamic Properties of Water and Steam', 2004.
@param p pressure in Pa
@param h enthalpy in J/kg
@return temperature in K
*/
double freesteam_region3_T_ph(double p, double h){
IAPWS97_APPROXIMATE;
double pi1, eta1;
double Tstar;
BackwardsData *d;
unsigned i, n;
double sum = 0;
if(REGION3_B3AB_PH(p,h) <= 0.){
/* sub-region 3a */
pi1 = p/REGION3A_TPH_PSTAR + 0.240; eta1 = h/REGION3A_TPH_HSTAR - 0.615;
d = REGION3A_TPH_DATA;
n = REGION3A_TPH_MAX;
Tstar = REGION3A_TPH_TSTAR;
}else{
/* sub-region 3b */
pi1 = p/REGION3B_TPH_PSTAR + 0.298; eta1 = h/REGION3B_TPH_HSTAR - 0.720;
d = REGION3B_TPH_DATA;
n = REGION3B_TPH_MAX;
Tstar = REGION3B_TPH_TSTAR;
}
for(i = 0; i<n; ++i, ++d){
sum += d->n * ipow(pi1, d->I) * ipow(eta1, d->J);
}
return sum * Tstar;
}
/*------------------------------------------------------------------------------
REGION 3 V(P,H)
*/
BackwardsData REGION3A_VPH_DATA[] = {
{-12, 6, 5.29944062966028E-03}
,{-12, 8, -0.170099690234461}
,{-12, 12, 11.1323814312927}
,{-12, 18, -2178.98123145125}
,{-10, 4, -5.06061827980875E-04}
,{-10, 7, 0.556495239685324}
,{-10, 10, -9.43672726094016}
,{-8, 5, -0.297856807561527}
,{-8, 12, 93.9353943717186}
,{-6, 3, 1.92944939465981E-02}
,{-6, 4, 0.421740664704763}
,{-6, 22, -3689141.2628233}
,{-4, 2, -7.37566847600639E-03}
,{-4, 3, -0.354753242424366}
,{-3, 7, -1.99768169338727}
,{-2, 3, 1.15456297059049}
,{-2, 16, 5683.6687581596}
,{-1, 0, 8.08169540124668E-03}
,{-1, 1, 0.172416341519307}
,{-1, 2, 1.04270175292927}
,{-1, 3, -0.297691372792847}
,{0, 0, 0.560394465163593}
,{0, 1, 0.275234661176914}
,{1, 0, -0.148347894866012}
,{1, 1, -6.51142513478515E-02}
,{1, 2, -2.92468715386302}
,{2, 0, 6.64876096952665E-02}
,{2, 2, 3.52335014263844}
,{3, 0, -1.46340792313332E-02}
,{4, 2, -2.24503486668184}
,{5, 2, 1.10533464706142}
,{8, 2, -4.08757344495612E-02}
};
const unsigned REGION3A_VPH_MAX = sizeof(REGION3A_VPH_DATA)/sizeof(BackwardsData);
BackwardsData REGION3B_VPH_DATA[] = {
{-12, 0, -2.25196934336318E-09}
,{-12, 1, 1.40674363313486E-08}
,{-8, 0, 2.3378408528056E-06}
,{-8, 1, -3.31833715229001E-05}
,{-8, 3, 1.07956778514318E-03}
,{-8, 6, -0.271382067378863}
,{-8, 7, 1.07202262490333}
,{-8, 8, -0.853821329075382}
,{-6, 0, -2.15214194340526E-05}
,{-6, 1, 7.6965608822273E-04}
,{-6, 2, -4.31136580433864E-03}
,{-6, 5, 0.453342167309331}
,{-6, 6, -0.507749535873652}
,{-6, 10, -100.475154528389}
,{-4, 3, -0.219201924648793}
,{-4, 6, -3.21087965668917}
,{-4, 10, 607.567815637771}
,{-3, 0, 5.57686450685932E-04}
,{-3, 2, 0.18749904002955}
,{-2, 1, 9.05368030448107E-03}
,{-2, 2, 0.285417173048685}
,{-1, 0, 3.29924030996098E-02}
,{-1, 1, 0.239897419685483}
,{-1, 4, 4.82754995951394}
,{-1, 5, -11.8035753702231}
,{0, 0, 0.169490044091791}
,{1, 0, -1.79967222507787E-02}
,{1, 1, 3.71810116332674E-02}
,{2, 2, -5.36288335065096E-02}
,{2, 6, 1.6069710109252}
};
const unsigned REGION3B_VPH_MAX = sizeof(REGION3B_VPH_DATA)/sizeof(BackwardsData);
const double REGION3A_VPH_HSTAR = 2100e3; /* J/kg */
const double REGION3A_VPH_PSTAR = 100.e6; /* Pa */
const double REGION3A_VPH_VSTAR = 0.0028; /* m³/kg */
const double REGION3B_VPH_HSTAR = 2800e3;
const double REGION3B_VPH_PSTAR = 100.e6;
const double REGION3B_VPH_VSTAR = 0.0088;
/**
Backward equation for specific volume in terms of pressure and enthalpy
in IAPWS-IF97 Region 3 (composed of sub-regions 3a, 3b).
Source: IAPWS 'Revised Supplementary Release on Backward Equations for the Functions
T(p,h), v(p,h) and T(p,s), v(p,s) for Region 3 of the IAPWS Industrial
Formulation 1997 for the Thermodynamic Properties of Water and Steam', 2004.
@param p pressure in Pa
@param h enthalpy in J/kg
@return temperature in K
*/
double freesteam_region3_v_ph(double p, double h){
IAPWS97_APPROXIMATE;
double pi1, eta1;
BackwardsData *d;
unsigned i, n;
double sum = 0;
double vstar;
if(REGION3_B3AB_PH(p,h) <= 0.){
/* sub-region 3a */
pi1 = p/REGION3A_VPH_PSTAR + 0.128; eta1 = h/REGION3A_VPH_HSTAR - 0.727;
d = REGION3A_VPH_DATA;
n = REGION3A_VPH_MAX;
vstar = REGION3A_VPH_VSTAR;
}else{
/* sub-region 3b */
pi1 = p/REGION3B_VPH_PSTAR + 0.0661; eta1 = h/REGION3B_VPH_HSTAR - 0.720;
d = REGION3B_VPH_DATA;
n = REGION3B_VPH_MAX;
vstar = REGION3B_VPH_VSTAR;
}
for(i = 0; i<n; ++i, ++d){
sum += d->n * ipow(pi1, d->I) * ipow(eta1, d->J);
}
return sum * vstar;
}
/*------------------------------------------------------------------------------
REGION 3 PSAT(H) BOUNDARY
*/
BackwardsData REGION3_PSATH_DATA[] = {
{ 0, 0, 0.600073641753024}
,{1, 1, -0.936203654849857e1}
,{1, 3, 0.246590798594147e2}
,{1, 4, -0.107014222858224e3}
,{1, 36, -0.915821315805768e14}
,{5, 3, -0.862332011700662e4}
,{7, 0, -0.235837344740032e2}
,{8, 24, 0.252304969384128e18}
,{14, 16, -0.389718771997719e19}
,{20, 16, -0.333775713645296e23}
,{22, 3, 0.356499469636328e11}
,{24, 18, -0.148547544720641e27}
,{28, 8, 0.330611514838798e19}
,{36, 24, 0.813641294467829e38}
};
const unsigned REGION3_PSATH_MAX = sizeof(REGION3_PSATH_DATA)/sizeof(BackwardsData);
const double REGION3_PSATH_HSTAR = 2600e3;
const double REGION3_PSATH_PSTAR = 22.e6;
double freesteam_region3_psat_h(double h){
IAPWS97_APPROXIMATE;
BackwardsData *d, *e = REGION3_PSATH_DATA + REGION3_PSATH_MAX;
double eta = h / REGION3_PSATH_HSTAR;
double eta1 = eta - 1.02;
double eta2 = eta - 0.608;
double sum = 0;
for(d = REGION3_PSATH_DATA; d<e; ++d){
sum += d->n * ipow(eta1, d->I) * ipow(eta2, d->J);
}
return sum * REGION3_PSATH_PSTAR;
}
/*------------------------------------------------------------------------------
REGION 3 PSAT(S) BOUNDARY
*/
BackwardsData REGION3_PSATS_DATA[] = {
{ 0, 0, 0.639767553612785}
, {1, 1, -0.129727445396014e2}
, {1, 32, -0.224595125848403e16}
, {4, 7, 0.177466741801846e7}
, {12, 4, 0.717079349571538e10}
, {12, 14, -0.378829107169011e18}
, {16, 36, -0.955586736431328e35}
, {24, 10, 0.187269814676188e24}
, {28, 0, 0.119254746466473e12}
, {32, 18, 0.110649277244882e37}
};
const unsigned REGION3_PSATS_MAX = sizeof(REGION3_PSATS_DATA)/sizeof(BackwardsData);
const double REGION3_PSATS_SSTAR = 5.2e3;
const double REGION3_PSATS_PSTAR = 22.e6;
double freesteam_region3_psat_s(double s){
IAPWS97_APPROXIMATE;
BackwardsData *d, *e = REGION3_PSATS_DATA + REGION3_PSATS_MAX;
double sig = s / REGION3_PSATS_SSTAR;
double sig1 = sig - 1.03;
double sig2 = sig - 0.699;
double sum = 0;
for(d = REGION3_PSATS_DATA; d<e; ++d){
sum += d->n * ipow(sig1, d->I) * ipow(sig2, d->J);
}
return sum * REGION3_PSATS_PSTAR;
}
/*------------------------------------------------------------------------------
REGION 3 BACKWARDS EQUATION T(P,S)
*/
/**
Source: Revised_Release_Tv3ph_Tv3ps_Rev3.doc sect 3.4
*/
BackwardsData REGION3A_TPS_DATA[] = {
{-12, 28, 1500420082.63875}
,{-12, 32, -159397258480.424}
,{-10, 4, 5.02181140217975E-04}
,{-10, 10, -67.2057767855466}
,{-10, 12, 1450.58545404456}
,{-10, 14, -8238.8953488889}
,{-8, 5, -0.154852214233853}
,{-8, 7, 11.2305046746695}
,{-8, 8, -29.7000213482822}
,{-8, 28, 43856513263.5495}
,{-6, 2, 1.37837838635464E-03}
,{-6, 6, -2.97478527157462}
,{-6, 32, 9717779473494.13}
,{-5, 0, -5.71527767052398E-05}
,{-5, 14, 28830.794977842}
,{-5, 32, -74442828926270.3}
,{-4, 6, 12.8017324848921}
,{-4, 10, -368.275545889071}
,{-4, 36, 6.64768904779177E+15}
,{-2, 1, 0.044935925195888}
,{-2, 4, -4.22897836099655}
,{-1, 1, -0.240614376434179}
,{-1, 6, -4.74341365254924}
,{0, 0, 0.72409399912611}
,{0, 1, 0.923874349695897}
,{0, 4, 3.99043655281015}
,{1, 0, 3.84066651868009E-02}
,{2, 0, -3.59344365571848E-03}
,{2, 3, -0.735196448821653}
,{3, 2, 0.188367048396131}
,{8, 0, 1.41064266818704E-04}
,{8, 1, -2.57418501496337E-03}
,{10, 2, 1.23220024851555E-03}
};
const unsigned REGION3A_TPS_MAX = sizeof(REGION3A_TPS_DATA)/sizeof(BackwardsData);
/**
Source: Revised_Release_Tv3ph_Tv3ps_Rev3.doc sect 3.4
*/
BackwardsData REGION3B_TPS_DATA[] = {
{-12, 1, 0.52711170160166}
,{-12, 3, -40.1317830052742}
,{-12, 4, 153.020073134484}
,{-12, 7, -2247.99398218827}
,{-8, 0, -0.193993484669048}
,{-8, 1, -1.40467557893768}
,{-8, 3, 42.6799878114024}
,{-6, 0, 0.752810643416743}
,{-6, 2, 22.6657238616417}
,{-6, 4, -622.873556909932}
,{-5, 0, -0.660823667935396}
,{-5, 1, 0.841267087271658}
,{-5, 2, -25.3717501764397}
,{-5, 4, 485.708963532948}
,{-5, 6, 880.531517490555}
,{-4, 12, 2650155.92794626}
,{-3, 1, -0.359287150025783}
,{-3, 6, -656.991567673753}
,{-2, 2, 2.41768149185367}
,{0, 0, 0.856873461222588}
,{2, 1, 0.655143675313458}
,{3, 1, -0.213535213206406}
,{4, 0, 5.62974957606348E-03}
,{5, 24, -316955725450471.}
,{6, 0, -6.99997000152457E-04}
,{8, 3, 1.19845803210767E-02}
,{12, 1, 1.93848122022095E-05}
,{14, 2, -2.15095749182309E-05}
};
const unsigned REGION3B_TPS_MAX = sizeof(REGION3B_TPS_DATA)/sizeof(BackwardsData);
const double REGION3A_TPS_TSTAR = 760.; /* K */
const double REGION3A_TPS_SSTAR = 4.4e3; /* J/kgK */
const double REGION3A_TPS_PSTAR = 100e6; /* Pa */
const double REGION3B_TPS_TSTAR = 860.; /* K */
const double REGION3B_TPS_SSTAR = 5.3e3; /* J/kgK */
const double REGION3B_TPS_PSTAR = 100e6; /* Pa */
const double REGION3AB_SC = 4.41202148223476e3; /* J/kgK */
/**
Backward equation for temperature in terms of pressure and entropy
in IAPWS-IF97 Region 3 (composed of sub-regions 3a, 3b).
Source: IAPWS 'Revised Supplementary Release on Backward Equations for the Functions
T(p,h), v(p,h) and T(p,s), v(p,s) for Region 3 of the IAPWS Industrial
Formulation 1997 for the Thermodynamic Properties of Water and Steam', 2004.
@param p pressure in Pa
@param s specific entropy in J/kgK
@return temperature in K
*/
double freesteam_region3_T_ps(double p, double s){
IAPWS97_APPROXIMATE;
double p1, s1;
double Tstar;
BackwardsData *d;
unsigned i, n;
double sum = 0;
if(s < REGION3AB_SC){
/* sub-region 3a */
p1 = p/REGION3A_TPS_PSTAR + 0.240; s1 = s/REGION3A_TPS_SSTAR - 0.703;
d = REGION3A_TPS_DATA;
n = REGION3A_TPS_MAX;
Tstar = REGION3A_TPS_TSTAR;
}else{
/* sub-region 3b */
p1 = p/REGION3B_TPS_PSTAR + 0.760; s1 = s/REGION3B_TPS_SSTAR - 0.818;
d = REGION3B_TPS_DATA;
n = REGION3B_TPS_MAX;
Tstar = REGION3B_TPS_TSTAR;
}
for(i = 0; i<n; ++i, ++d){
sum += d->n * ipow(p1, d->I) * ipow(s1, d->J);
}
return sum * Tstar;
}
/**
Source: Revised_Release_Tv3ph_Tv3ps_Rev3.doc sect 3.4
*/
BackwardsData REGION3A_VPS_DATA[] = {
{-12, 10, 0.795544074093975e2}
, {-12, 12, -0.238261242984590e4}
, {-12, 14, 0.176813100617787e5}
, {-10, 4, -0.110524727080379e-2}
, {-10, 8, -0.153213833655326e2}
, {-10, 10, 0.297544599376982e3}
, {-10, 20, -0.350315206871242e8}
, {-8, 5, 0.277513761062119}
, {-8, 6, -0.523964271036888}
, {-8, 14, -0.148011182995403e6}
, {-8, 16, 0.160014899374266e7}
, {-6, 28, 0.170802322663427e13}
, {-5, 1, 0.246866996006494e-3}
, {-4, 5, 0.165326084797980e1}
, {-3, 2, -0.118008384666987}
, {-3, 4, 0.253798642355900e1}
, {-2, 3, 0.965127704669424}
, {-2, 8, -0.282172420532826e2}
, {-1, 1, 0.203224612353823}
, {-1, 2, 0.110648186063513e1}
, {0, 0, 0.526127948451280}
, {0, 1, 0.277000018736321}
, {0, 3, 0.108153340501132e1}
, {1, 0, -0.744127885357893e-1}
, {2, 0, 0.164094443541384e-1}
, {4, 2, -0.680468275301065e-1}
, {5, 2, 0.257988576101640e-1}
, {6, 0, -0.145749861944416e-3}
};
const unsigned REGION3A_VPS_MAX = sizeof(REGION3A_VPS_DATA)/sizeof(BackwardsData);
/**
Source: Revised_Release_Tv3ph_Tv3ps_Rev3.doc sect 3.4
*/
BackwardsData REGION3B_VPS_DATA[] = {
{-12, 0, 0.591599780322238e-4}
, {-12, 1, -0.185465997137856e-2}
, {-12, 2, 0.104190510480013e-1}
, {-12, 3, 0.598647302038590e-2}
, {-12, 5, -0.771391189901699}
, {-12, 6, 0.172549765557036e1}
, {-10, 0, -0.467076079846526e-3}
, {-10, 1, 0.134533823384439e-1}
, {-10, 2, -0.808094336805495e-1}
, {-10, 4, 0.508139374365767}
, {-8, 0, 0.128584643361683e-2}
, {-5, 1, -0.163899353915435e1}
, {-5, 2, 0.586938199318063e1}
, {-5, 3, -0.292466667918613e1}
, {-4, 0, -0.614076301499537e-2}
, {-4, 1, 0.576199014049172e1}
, {-4, 2, -0.121613320606788e2}
, {-4, 3, 0.167637540957944e1}
, {-3, 1, -0.744135838773463e1}
, {-2, 0, 0.378168091437659e-1}
, {-2, 1, 0.401432203027688e1}
, {-2, 2, 0.160279837479185e2}
, {-2, 3, 0.317848779347728e1}
, {-2, 4, -0.358362310304853e1}
, {-2, 12, -0.115995260446827e7}
, {0, 0, 0.199256573577909}
, {0, 1, -0.122270624794624}
, {0, 2, -0.191449143716586e2}
, {1, 0, -0.150448002905284e-1}
, {1, 2, 0.146407900162154e2}
, {2, 2, -0.327477787188230e1}
};
const unsigned REGION3B_VPS_MAX = sizeof(REGION3B_VPS_DATA)/sizeof(BackwardsData);
const double REGION3A_VPS_VSTAR = 0.0028; /* kg/m³ */
const double REGION3A_VPS_SSTAR = 4.4e3; /* J/kgK */
const double REGION3A_VPS_PSTAR = 100e6; /* Pa */
const double REGION3B_VPS_VSTAR = 0.0088; /* kg/m³ */
const double REGION3B_VPS_SSTAR = 5.3e3; /* J/kgK */
const double REGION3B_VPS_PSTAR = 100e6; /* Pa */
/**
Backward equation for temperature in terms of pressure and entropy
in IAPWS-IF97 Region 3 (composed of sub-regions 3a, 3b).
Source: IAPWS 'Revised Supplementary Release on Backward Equations for the Functions
T(p,h), v(p,h) and T(p,s), v(p,s) for Region 3 of the IAPWS Industrial
Formulation 1997 for the Thermodynamic Properties of Water and Steam', 2004.
@param p pressure in Pa
@param s specific entropy in J/kgK
@return temperature in K
*/
double freesteam_region3_v_ps(double p, double s){
IAPWS97_APPROXIMATE;
double p1, s1;
double vstar;
BackwardsData *d;
unsigned i, n;
double sum = 0;
if(s < REGION3AB_SC){
/* sub-region 3a */
//fprintf(stderr,"3A\n");
p1 = p/REGION3A_VPS_PSTAR + 0.187; s1 = s/REGION3A_VPS_SSTAR - 0.755;
d = REGION3A_VPS_DATA;
n = REGION3A_VPS_MAX;
vstar = REGION3A_VPS_VSTAR;
}else{
/* sub-region 3b */
//fprintf(stderr,"3B\n");
p1 = p/REGION3B_VPS_PSTAR + 0.298; s1 = s/REGION3B_VPS_SSTAR - 0.816;
d = REGION3B_VPS_DATA;
n = REGION3B_VPS_MAX;
vstar = REGION3B_VPS_VSTAR;
}
for(i = 0; i<n; ++i, ++d){
sum += d->n * ipow(p1, d->I) * ipow(s1, d->J);
}
return sum * vstar;
}

View file

@ -0,0 +1,35 @@
/*
freesteam - IAPWS-IF97 steam tables library
Copyright (C) 2004-2009 John Pye
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef FREESTEAM_BACKWARDS_H
#define FREESTEAM_BACKWARDS_H
#include "common.h"
FREESTEAM_DLL double freesteam_region1_T_ph(double p, double h);
FREESTEAM_DLL double freesteam_region2_T_ph(double p, double h);
FREESTEAM_DLL double freesteam_region3_T_ph(double p, double h);
FREESTEAM_DLL double freesteam_region3_v_ph(double p, double h);
FREESTEAM_DLL double freesteam_region3_psat_h(double h);
FREESTEAM_DLL double freesteam_region3_psat_s(double s);
FREESTEAM_DLL double freesteam_region3_T_ps(double p, double h);
FREESTEAM_DLL double freesteam_region3_v_ps(double p, double h);
#endif

View file

@ -0,0 +1,61 @@
/*
freesteam - IAPWS-IF97 steam tables library
Copyright (C) 2004-2009 John Pye
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*//** @file
Implementation details for backwards equations. Intended that
this header file would only be used for internal tests etc.
*/
#ifndef FREESTEAM_BACKWARDS_IMPL_H
#define FREESTEAM_BACKWARDS_IMPL_H
#include "common.h"
#define SQ(X) ((X)*(X))
#define CUBE(X) ((X)*(X)*(X))
/* boundary between subregions 3a and 3b in region 3 for (p,h) */
#define REGION3_B3AB_PSTAR (1.e6)
#define REGION3_B3AB_HSTAR (1.e3)
#define REGION3_B3AB_ETA(H) ((H)/REGION3_B3AB_HSTAR)
#define REGION3_B3AB_PI(P) ((P)/REGION3_B3AB_PSTAR)
#define REGION3_B3AB_PH(P,H) (REGION3_B3AB_ETA(H) - (\
2014.64004206875 \
+ 3.74696550136983*REGION3_B3AB_PI(P) \
- 2.19921901054187E-02 * SQ(REGION3_B3AB_PI(P)) \
+ 8.7513168600995E-05 * CUBE(REGION3_B3AB_PI(P)) \
))
/* boundary between subregions 2 and 3 in region 2 for (p,h) */
#define REGION2_B2BC_PSTAR (1.e6)
#define REGION2_B2BC_HSTAR (1.e3)
#define REGION2_B2BC_ETA(H) ((H)/REGION2_B2BC_HSTAR)
#define REGION2_B2BC_PI(P) ((P)/REGION2_B2BC_PSTAR)
#define REGION2_B2BC_PH(P,H) (\
(REGION2_B2BC_PI(P) - (\
905.84278514723 \
- 0.67955786399241*REGION2_B2BC_ETA(H) \
+ 1.2809002730136E-04 * SQ(REGION2_B2BC_ETA(H)) \
)))
#endif

View file

@ -0,0 +1,43 @@
/*
freesteam - IAPWS-IF97 steam tables library
Copyright (C) 2004-2005 John Pye
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#define FREESTEAM_BUILDING_LIB
#include "common.h"
/* ipow: public domain by Mark Stephen with suggestions by Keiichi Nakasato */
double ipow(double x, int n){
double t = 1.0;
if(!n)return 1.0; /* At the top. x^0 = 1 */
if (n < 0){
n = -n;
x = 1.0/x; /* error if x == 0. Good */
} /* ZTC/SC returns inf, which is even better */
if (x == 0.0)return 0.0;
do{
if(n & 1)t *= x;
n /= 2; /* KN prefers if (n/=2) x*=x; This avoids an */
x *= x; /* unnecessary but benign multiplication on */
}while(n); /* the last pass, but the comparison is always
true _except_ on the last pass. */
return t;
}

View file

@ -0,0 +1,112 @@
/*
freesteam - IAPWS-IF97 steam tables library
Copyright (C) 2004-2005 John Pye
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef FREESTEAM_COMMON_H
#define FREESTEAM_COMMON_H
#include "config.h"
#define FREESTEAM_CHAR int
/*
ASCEND code in base/generic only EXPORTS symbols, no imports.
The FREESTEAM_DLLSPEC macro will, depending on whether we are
FREESTEAM_BUILDING_LIBASCEND (building libascend.so aka ascend.dll)
or FREESTEAM_BUILDING_INTERFACE (building for example _ascpy.dll or
ascendtcl.dll), act respectively to declare symbols as being
*exported* or *imported*.
New versions of GCC are able to make use of these declarations
as well.
*/
#ifdef __WIN32__
# define FREESTEAM_EXPORT __declspec(dllexport)
# define FREESTEAM_IMPORT __declspec(dllimport)
#else
# ifdef HAVE_GCCVISIBILITY
# define FREESTEAM_EXPORT __attribute__ ((visibility("default")))
# define FREESTEAM_IMPORT
# else
# define FREESTEAM_EXPORT
# define FREESTEAM_IMPORT
# endif
#endif
#ifdef FREESTEAM_BUILDING_LIB
# define FREESTEAM_DLL extern FREESTEAM_EXPORT
#else
# define FREESTEAM_DLL extern FREESTEAM_IMPORT
#endif
#if !defined(FREESTEAM_DLL) || !defined(FREESTEAM_EXPORT) || !defined(FREESTEAM_IMPORT)
# error "NO FREESTEAM_DLL DEFINED"
#endif
/* Constants used throughout IAPWS-IF97 */
#define IAPWS97_PMAX 100e6 /* Pa */
#define IAPWS97_TMIN 273.15 /* K */
#define IAPWS97_TMAX 1073.15 /* K */
#define IAPWS97_TCRIT 647.096 /* K */
#define IAPWS97_PCRIT 22.064e6 /* Pa */
#define IAPWS97_RHOCRIT 322. /* kg/m³ */
#define IAPWS97_PTRIPLE 611.657 /* Pa */
#define IAPWS97_R 461.526 /* J/kgK */
//#define IAPWS97_WARN_APPROX
#ifndef __GNUC__
# define __func__ "<function>"
#endif
//#include <stdio.h>
#ifdef IAPWS97_WARN_APPROX
# define IAPWS97_APPROXIMATE \
static char _warn_approx=0; \
if(!_warn_approx){ \
_warn_approx = 1; \
fprintf(stderr \
,"WARNING: %s (%s:%d): backwards or approximation function used!\n" \
,__func__,__FILE__,__LINE__ \
); \
}
#else
# define IAPWS97_APPROXIMATE
#endif
#define SQ(X) ((X)*(X))
/* Basic math routines, if necesary... */
FREESTEAM_DLL double freesteam_ipow(double x, int n);
#ifdef FREESTEAM_BUILDING_LIB
/* our local ipow implementation */
# define ipow freesteam_ipow
/* 'isnan' function for use with Windows */
# ifdef WIN32
# include <float.h>
# define isnan _isnan
# endif
#endif
#endif /* FREESTEAM_COMMON_H */

View file

@ -0,0 +1,499 @@
/*
freesteam - IAPWS-IF97 steam tables library
Copyright (C) 2004-2005 John Pye
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/** @file
This file contains some initial attempts at a compatibility wrapping of
freesteam 2.0 to enable it to be called using syntax hopefully identical to,
or at least approaching, that used in freesteam 0.8.1.
John Pye, Mar 2010.
*/
#ifndef FREESTEAM_COMPAT_H
#define FREESTEAM_COMPAT_H
extern "C"{
#include <freesteam/steam.h>
#include <freesteam/steam_ph.h>
#include <freesteam/steam_pT.h>
#include <freesteam/steam_ps.h>
#include <freesteam/steam_Ts.h>
#include <freesteam/steam_Tx.h>
#include <freesteam/region4.h>
};
template<class T>
T sq(const T& t){
return t*t;
};
typedef double Num;
/* UNITS OF MEASUREMENT ALL REDUCED TO DOUBLES */
//--------------------------------
// BASE MEASURES
typedef double Mass;
typedef double Length;
typedef double Time;
typedef double Temperature;
typedef double Current;
//--------------------------------
// DERIVED MEASURES
typedef double Area;
typedef double Volume;
typedef double Density;
typedef double SpecificVolume;
typedef double DensityPerTime;
typedef double Frequency;
typedef double Force;
typedef double Pressure;
typedef double Velocity;
typedef double Acceleration;
typedef double Torque;
typedef double Energy;
typedef double Power;
typedef double SpecificEnergy;
typedef double DynamicViscosity;
typedef double KinematicViscosity;
typedef double PowerPerLength;
typedef double PressurePerLength;
typedef double ForcePerLength;
typedef double PowerPerMass;
typedef double DensitySpecificEnergyPerTime;
typedef double VolFlowRate;
typedef double MassFlowRate;
typedef double MassFlowRatePerLength;
typedef double MassFlowRatePerTime;
typedef double HeatFlux;
typedef double MassFlux;
// Thermodynamics
typedef double Entropy;
typedef double SpecificEntropy;
typedef double ThermalConductivity;
typedef double HeatTransferCoefficient;
typedef double ThermalResistance;
typedef double HeatCapacityPerLength;
typedef double PowerPerTemperature;
typedef double ThermalExpansionCoefficient;
// Electrical
typedef double Charge;
typedef double ElecPotential;
typedef double Capacitance;
typedef double Resistance;
typedef double Conductance;
//----------------------------------------------
// BASE UNITS FOR BASE MEASURES
#define kilogram 1.0
#define metre 1.0
#define second 1.0
#define Kelvin 1.0
#define ampere 1.0
//------------------------------------
// SOME ALTERNATIVE NAMES
typedef Velocity Speed;
typedef Length Distance;
typedef Energy Heat;
typedef Heat Work; // nice
typedef Power HeatRate;
typedef PowerPerLength HeatRatePerLength;
typedef PowerPerTemperature HeatRatePerTemperature;
typedef Pressure Stress;
typedef HeatTransferCoefficient HTCoeff;
typedef SpecificEntropy SpecificHeatCapacity; // not the same but the units are the same
typedef SpecificHeatCapacity SpecHeatCap;
typedef SpecificHeatCapacity SpecificGasConstant;
typedef SpecificGasConstant SpecGasConst;
typedef ForcePerLength SurfaceTension;
//------------------------------------
// SI MULTIPLIERS
const double Tera = 1e12;
const double Giga = 1e9;
const double Mega = 1e6;
const double kilo = 1e3;
const double hecta = 1e2;
const double Deca = 10;
const double deci = 0.1;
const double centi = 1e-2;
const double milli = 1e-3;
const double micro = 1e-6;
//------------------------------------
// COMMON MEASURES (SI)
const Mass gram = milli * kilogram;
const Mass kg = kilogram;
const Length centimetre = metre / 100.0;
const Length kilometre = 1000.0 * metre;
const Area metre2 = metre * metre;
const Area hectare = (100.0 * metre) * (100.0 * metre);
const Volume metre3 = metre2 * metre;
const Volume litre = milli * metre3;
const Volume centimetre3 =
(centi * metre) * (centi * metre) * (centi * metre);
const Time minute = 60.0 * second;
const Time hour = 60.0 * minute;
const Time day = 24.0 * hour;
const Frequency Hertz = 1.0 / second;
const Force Newton = kilogram * metre / (second * second);
const Pressure Pascal = Newton / (metre * metre);
const Pressure bar = 100.0 * kilo * Pascal;
const Pressure MPa = Mega * Pascal;
const Pressure kPa = kilo * Pascal;
const Energy Joule = Newton * metre;
const Energy kJ = kilo * Joule;
const Energy Btu = 1055.05585262 * Joule;
const Power Watt = Joule / second;
const HeatFlux W_m2 = Watt / metre2;
const double Percent = 1.0 / 100;
//------------------------------------
// THERMODYNAMIC MEASURES
const SpecificEnergy kJ_kg = kilo * Joule / kilogram;
const SpecificEnergy J_kg = Joule / kilogram;
const SpecificEntropy kJ_kgK = kilo * Joule / kilogram / Kelvin;
const SpecificEntropy J_kgK = Joule / kilogram / Kelvin;
const HeatTransferCoefficient W_m2K = Watt / metre2 / Kelvin;
const ThermalConductivity W_mK = Watt / metre / Kelvin;
const ThermalConductivity mW_mK = milli * W_mK;
const Density kg_m3 = kilogram / metre3;
const SpecificVolume m3_kg = metre3 / kilogram;
const MassFlowRate kg_s = kilogram / second;
const VolFlowRate m3_s = metre3 / second;
const HeatCapacityPerLength J_mK = Joule / metre / Kelvin;
//------------------------------------
// ELECTRICAL STUFF
const ElecPotential volt = Watt / ampere;
const Charge Coulomb = ampere * second;
const Capacitance Farad = volt / Coulomb;
const Resistance Ohm = volt / ampere;
//------------------------------------
// SOME IMPERIAL MEASURES
const Temperature Rankin = 0.556 * Kelvin;
const Frequency RPM = 1. / minute;
const Length yard = 0.9144 * metre;
const Length foot = yard / 3.;
const Length inch = foot / 12.;
const Length mile = 1760. * yard;
const Mass lbm = 0.45359237 * kilogram;
const Acceleration grav_accel = 9.80665 * metre / second / second;
const Force lbf = grav_accel * lbm;
const Pressure lbf_in2 = lbf / inch / inch;
//------------------------------------
// HANDLING TEMPERATURES
const Temperature ZeroCelsius = 273.15 * Kelvin;
const Temperature ZeroFahrenheit = ZeroCelsius - 32.0 * Rankin;
/**
Convert a temperature (in Kelvin) to Celsius.
@return the temperature, as a plain 'double' type
*/
inline double
tocelsius(const Temperature& T){
double d = *reinterpret_cast<const double*>(&T);
return d - 273.15;
}
/**
Convert a Celsius temperature to Kelvin
@param T_C double value for the temperature in degrees
@return Temperature object (Kelvin)
*/
inline Temperature
fromcelsius(const double &T_C){
return (T_C * Kelvin) + ZeroCelsius;
}
/**
Convert from Fahrenheit temperature to Temperature object (Kelvin)
*/
inline double
tofahrenheit(const Temperature &T){
return (T - ZeroFahrenheit) / Rankin;
}
/// Convert Temperature object to Fahrenheit
/**
@return temperature in Fahrenheit (as type 'double')
*/
inline Temperature
fromfahrenheit(const double &T_F){
return (T_F * Rankin) + ZeroFahrenheit;
}
// USEFUL CONSTANTS
/// Stefan-Boltzmann Constant (radiation)
const double SIGMA_C = (5.670e-8) * W_m2 /sq(sq(Kelvin));
/* STEAM-SPECIFIC CONSTANTS */
const SpecificGasConstant R=0.461526 * kJ_kgK; // Specific gas constant for water from IF97
#define REG4_TOL 0.001 // relative err on pressures considerd to be equal to psat.
const Temperature TB_HIGH = 863.15 * Kelvin;
const Temperature T_MIN = ZeroCelsius;
const Temperature T_MAX = 1073.15 * Kelvin;
const Temperature T_CRIT = 647.096 * Kelvin; // critical-point temperature
const Temperature T_TRIPLE = 273.16 * Kelvin; // triple-point temperature
const Temperature REG2_TEMP_REF = 540.0 * Kelvin;
const Temperature REG1_TEMP_REF = 1386.0 * Kelvin;
const Temperature REG1_T_LOW = ZeroCelsius;
const Temperature REG2_T_LOW = ZeroCelsius;
const Temperature REG2_T_HIGH = T_MAX;
const Temperature T_REG1_REG3 = 623.15 * Kelvin;
const Temperature TB_LOW = T_REG1_REG3;
const Temperature T_MIN_VOL = fromcelsius(3.984);
const Pressure P_MAX = 100.0 * MPa;
const Pressure PB_LOW = 16.5292 * MPa;
const Pressure P_MIN = 0.0 * Pascal;
const Pressure P_CRIT = 22.064 * MPa; // critical-point pressure
const Pressure P_TRIPLE = 611.657 * Pascal; // triple-point pressure
const Pressure REG4_P_MIN = 611.213 * Pascal; // minimum pressure for region 4 (IF-97 eq 31 & p 35) / [MPa]
const Pressure REG2_P_HIGH = P_MAX;
const Pressure REG1_P_HIGH = P_MAX;
const Pressure REG1_PRES_REF = 16.53 * MPa;
const Pressure REG2_PRES_REF = 1.0 * MPa;
const Density RHO_CRIT = 322.0 * kg / metre3; // critical-point density / [kg/m³]
/// @see http://www.iapws.org/relguide/visc.pdf#page=7 Eq (4)
const DynamicViscosity IAPS85_VISC_REF = 55.071 * micro * Pascal * second;
/// @see http://www.iapws.org/relguide/visc.pdf#page=7 Eq (2)
const Density IAPS85_DENS_REF = 317.763 * kg_m3;
/// @see http://www.iapws.org/relguide/visc.pdf#page=7 Eq (1)
const Temperature IAPS85_TEMP_REF = 647.226 * Kelvin;
/// @see http://www.iapws.org/relguide/visc.pdf#page=7 Eq (4)
const Pressure IAPS85_PRES_REF = 22.115 * MPa; // MPa (THIS IS *NOT* EQUAL TO P_CRIT!)
const Temperature IAPS85_TEMP_REG2_REF = 540.0 * Kelvin;
const Pressure STEAM_P_EPS = 1.0e-5 * MPa;
const Temperature STEAM_T_EPS = 5.0e-4 * Kelvin;
const Temperature EPS_T_CRIT=0.00007 * Kelvin;
const Temperature T_CRIT_PLUS=(T_CRIT + STEAM_T_EPS);
const Density REG3_ZEROIN_DENS_MAX = 765.0 * kg_m3;
const Density REG3_ZEROIN_TOL= 1e-18 * kg_m3;
#define MPA_TO_BAR(PRES) (((Num)(PRES)) * 10.0 )
#define BAR_TO_MPA(PRES) (((Num)(PRES)) * 0.1 )
#define PA_TO_MPA(PRES) (((Num)(PRES)) * 0.000001 )
#define MPA_TO_PA(PRES) (((Num)(PRES)) * 1.0E6 )
#define KJKG_TO_JKG(JKG) (((Num)(KJKG)) * 1000.0 )
#define BAR_TO_PA(PRES) (((Num)(PRES)) * 100.0E3 )
#define KPA_TO_MPA(PRES) (((Num)(PRES)) * 0.001 )
#define W_TO_KW(W) (((Num)(W))*0.001)
#define KJ_TO_J(KJ) (((Num)(KJ))*0.001)
#define J_TO_KJ(J) (((Num)(J))*0.001)
const Acceleration GRAV = 9.81 * Newton / kg; // N/kg, gravitation acceleration
#ifndef PI
# define PI 3.14159265358
#endif
typedef enum{SOLVE_IENERGY, SOLVE_ENTHALPY, SOLVE_ENTROPY, SOLVE_CP, SOLVE_CV, SOLVE_TEMPERATURE, SOLVE_PRESSURE} SolveParam;
typedef SteamState SteamSolveFunction(double, double);
typedef int SteamRegionFunction(double, double);
typedef int SteamBoundsFunction(double, double, int);
class SteamCalculator{
private:
SteamState S;
public:
SteamCalculator(){
S.region = 1;
S.R1.T = 300;
S.R1.p = 1e5;
}
SteamCalculator(const SteamState &S1){
S = S1;
}
/// Copy constructor
SteamCalculator(const SteamCalculator & original){
S = original.S;
}
/// Assignment operator (assigns a copy)
SteamCalculator const &operator=(SteamCalculator const &original){
S = original.S;
}
// Destructor
~SteamCalculator(){}
// Defining state, simple methods
inline void set_pT(const Pressure &p, const Temperature &T){
S = freesteam_set_pT(p,T);
}
inline void setSatWater_p(const Pressure &p){
S = freesteam_set_Tx(freesteam_region4_Tsat_p(p), 0.0);
}
inline void setSatSteam_p(const Pressure &p){
S = freesteam_set_Tx(freesteam_region4_Tsat_p(p), 1.0);
}
inline void setSatWater_T(const Temperature &T){
S = freesteam_set_Tx(T, 0.0);
}
inline void setSatSteam_T(const Temperature &T){
S = freesteam_set_Tx(T, 1.0);
}
inline void setRegion1_pT(const Pressure &p, const Temperature &T){
S.region = 1;
S.R1.p = p;
S.R1.T = T;
}
inline void setRegion2_pT(const Pressure &p, const Temperature &T){
S.region = 2;
S.R2.p = p;
S.R2.T = T;
}
inline void setRegion4_Tx(const Temperature &T, const Num &x){
S.region = 4;
S.R4.T = T;
S.R4.x = x;
}
inline void setRegion3_rhoT(const Density &rho, const Temperature &T){
S.region = 3;
S.R3.T = T;
S.R3.rho = rho;
}
// Methods to return properties and state
inline int whichRegion(void) const{
return S.region;
}
inline double temp() const{return freesteam_T(S);}
inline double pres() const{return freesteam_p(S);}
inline double dens() const{return 1./freesteam_v(S);}
inline double specvol() const{return freesteam_v(S);}
inline double specienergy() const{return freesteam_u(S);}
inline double specentropy() const{return freesteam_s(S);}
inline double specenthalpy() const{return freesteam_h(S);}
inline double speccp() const{return freesteam_cp(S);}
inline double speccv() const{return freesteam_cv(S);}
inline double quality() const{return freesteam_x(S);}
inline double dynvisc() const{return freesteam_mu(S);}
inline double conductivity() const{return freesteam_k(S);}
};
template<SolveParam FirstProp, SolveParam SecondProp>
class Solver2{
private:
SteamSolveFunction *solvefunc;
SteamRegionFunction *regionfunc;
SteamBoundsFunction *boundfunc;
public:
Solver2();
~Solver2(){}
inline int whichRegion(const double &fp, const double &sp){return (*regionfunc)(fp,sp);}
inline SteamCalculator solve(const double &fp, const double &sp){return SteamCalculator((*solvefunc)(fp,sp));}
/* ignore any provided guesses, we can't use those currently in freesteam 2.0 */
inline SteamState solve(const double &fp, const double &sp, const SteamCalculator firstguess){return SteamCalculator((*solvefunc)(fp,sp));}
};
template<>
Solver2<SOLVE_PRESSURE, SOLVE_TEMPERATURE>::Solver2()
: solvefunc(&freesteam_set_ph), regionfunc(&freesteam_region_ph), boundfunc(&freesteam_bounds_ph)
{}
template<>
Solver2<SOLVE_TEMPERATURE, SOLVE_ENTROPY>::Solver2()
: solvefunc(&freesteam_set_Ts), regionfunc(&freesteam_region_Ts), boundfunc(&freesteam_bounds_Ts)
{}
#endif

View file

@ -0,0 +1,7 @@
#ifndef FREESTEAM_CONFIG_H
#define FREESTEAM_CONFIG_H
#define FREESTEAM_VERSION "2.1"
#endif

View file

@ -0,0 +1,195 @@
/*
freesteam - IAPWS-IF97 steam tables library
Copyright (C) 2004-2009 John Pye
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#define FREESTEAM_BUILDING_LIB
#include "region1.h"
static double gam(double pi, double tau);
static double gampi(double pi, double tau);
static double gampipi(double pi, double tau);
static double gamtau(double pi, double tau);
static double gamtautau(double pi, double tau);
static double gampitau(double pi, double tau);
#define REGION1_GPT_PSTAR 16.53e6 /* Pa */
#define REGION1_GPT_TSTAR 1386. /* K */
#define DEFINE_PITAU(P,T) \
double pi = p / REGION1_GPT_PSTAR; \
double tau = REGION1_GPT_TSTAR / T
#define R IAPWS97_R
#include <math.h>
double freesteam_region1_u_pT(double p, double T){
DEFINE_PITAU(P,T);
return (R * T) * (tau * gamtau(pi,tau) - pi * gampi(pi,tau));
}
double freesteam_region1_v_pT(double p, double T){
DEFINE_PITAU(P,T);
return (R * T / p) * pi * gampi(pi,tau);
}
double freesteam_region1_s_pT(double p, double T){
DEFINE_PITAU(P,T);
return R * (tau * gamtau(pi,tau) - gam(pi,tau));
}
double freesteam_region1_h_pT(double p, double T){
DEFINE_PITAU(P,T);
return R * T * (tau * gamtau(pi,tau));
}
double freesteam_region1_cp_pT(double p, double T){
DEFINE_PITAU(P,T);
return R * (-SQ(tau) * gamtautau(pi,tau));
}
double freesteam_region1_cv_pT(double p, double T){
DEFINE_PITAU(P,T);
return R * (-SQ(tau) * gamtautau(pi,tau) + SQ(gampi(pi,tau) -
tau * gampitau(pi,tau)) / gampipi(pi,tau)
);
}
double freesteam_region1_w_pT(double p, double T){
DEFINE_PITAU(P,T);
double gp = gampi(pi,tau);
return sqrt(R * T * SQ(gp) / \
(SQ(gp - tau*gampitau(pi,tau))/SQ(tau)/gamtautau(pi,tau) - gampipi(pi,tau))
);
}
double freesteam_region1_g_pT(double p, double T){
DEFINE_PITAU(p,T);
return R * T * gam(pi,tau);
}
double freesteam_region1_a_pT(double p, double T){
DEFINE_PITAU(p,T);
return R * T * (gam(pi,tau) - gampi(pi,tau) * pi);
}
double freesteam_region1_alphav_pT(double p, double T){
DEFINE_PITAU(P,T);
return 1./T * (1. - tau*gampitau(pi,tau)/gampi(pi,tau));
}
double freesteam_region1_kappaT_pT(double p, double T){
DEFINE_PITAU(P,T);
return -1./p * pi*gampipi(pi,tau)/gampi(pi,tau);
}
//----------------------------------------------------------------
// REGION 1 G(p,T) EQUATIONS
typedef struct{
int I, J;
double n;
} IJNData;
const IJNData REGION1_GPT_DATA[] = {
{0, -2, 0.14632971213167E+00}
,{0, -1, -0.84548187169114E+00}
,{0, 0, -0.37563603672040E+01}
,{0, 1, 0.33855169168385E+01}
,{0, 2, -0.95791963387872E+00}
,{0, 3, 0.15772038513228E+00}
,{0, 4, -0.16616417199501E-01}
,{0, 5, 0.81214629983568E-03}
,{1, -9, 0.28319080123804E-03}
,{1, -7, -0.60706301565874E-03}
,{1, -1, -0.18990068218419E-01}
,{1, 0, -0.32529748770505E-01}
,{1, 1, -0.21841717175414E-01}
,{1, 3, -0.52838357969930E-04}
,{2, -3, -0.47184321073267E-03}
,{2, 0, -0.30001780793026E-03}
,{2, 1, 0.47661393906987E-04}
,{2, 3, -0.44141845330846E-05}
,{2, 17, -0.72694996297594E-15}
,{3, -4, -0.31679644845054E-04}
,{3, 0, -0.28270797985312E-05}
,{3, 6, -0.85205128120103E-09}
,{4, -5, -0.22425281908000E-05}
,{4, -2, -0.65171222895601E-06}
,{4, 10, -0.14341729937924E-12}
,{5, -8, -0.40516996860117E-06}
,{8, -11, -0.12734301741641E-08}
,{8, -6, -0.17424871230634E-09}
,{21, -29, -0.68762131295531E-18}
,{23, -31, 0.14478307828521E-19}
,{29, -38, 0.26335781662795E-22}
,{30, -39, -0.11947622640071E-22}
,{31, -40, 0.18228094581404E-23}
,{32, -41, -0.93537087292458E-25}
};
const unsigned REGION1_GPT_MAX = sizeof(REGION1_GPT_DATA)/sizeof(IJNData);
#define REGION1_GPT_LOOP \
double sum = 0; \
const IJNData *d, *e = REGION1_GPT_DATA + REGION1_GPT_MAX; \
for(d = REGION1_GPT_DATA; d < e; ++d)
double gam(double pi, double tau){
REGION1_GPT_LOOP{
sum += d->n * ipow(7.1 - pi,d->I) * ipow(tau - 1.222,d->J);
}
return sum;
}
double gampi(double pi, double tau){
REGION1_GPT_LOOP{
sum += -d->n * d->I * ipow(7.1 - pi,d->I -1) * ipow(tau - 1.222,d->J);
}
return sum;
}
double gampipi(double pi, double tau){
REGION1_GPT_LOOP{
sum += d->n * d->I * (d->I - 1) * ipow(7.1 - pi, d->I - 2) * ipow(tau - 1.222, d->J);
}
return sum;
}
double gamtau(double pi, double tau){
REGION1_GPT_LOOP{
sum += d->n * ipow(7.1 - pi, d->I) * d->J * ipow(tau - 1.222, d->J - 1);
}
return sum;
}
double gamtautau(double pi, double tau){
REGION1_GPT_LOOP{
sum += d->n * ipow(7.1 - pi, d->I) * d->J * (d->J - 1) * ipow(tau - 1.222, d->J - 2);
}
return sum;
}
double gampitau(double pi, double tau){
REGION1_GPT_LOOP{
sum += -d->n * d->I * ipow(7.1 - pi, d->I - 1) * d->J * ipow(tau - 1.222, d->J - 1);
}
return sum;
}

View file

@ -0,0 +1,42 @@
/*
freesteam - IAPWS-IF97 steam tables library
Copyright (C) 2004-2009 John Pye
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef FREESTEAM_REGION1_H
#define FREESTEAM_REGION1_H
#include "common.h"
FREESTEAM_DLL double freesteam_region1_u_pT(double p, double T);
FREESTEAM_DLL double freesteam_region1_v_pT(double p, double T);
FREESTEAM_DLL double freesteam_region1_s_pT(double p, double T);
FREESTEAM_DLL double freesteam_region1_h_pT(double p, double T);
FREESTEAM_DLL double freesteam_region1_cp_pT(double p, double T);
FREESTEAM_DLL double freesteam_region1_cv_pT(double p, double T);
FREESTEAM_DLL double freesteam_region1_w_pT(double p, double T);
FREESTEAM_DLL double freesteam_region1_a_pT(double p, double T);
FREESTEAM_DLL double freesteam_region1_g_pT(double p, double T);
/* used in calculations of derivatives, see derivs.c */
double freesteam_region1_alphav_pT(double p, double T);
double freesteam_region1_kappaT_pT(double p, double T);
#define REGION1_TMAX 623.15 /* K */
#endif

View file

@ -0,0 +1,280 @@
/*
freesteam - IAPWS-IF97 steam tables library
Copyright (C) 2004-2009 John Pye
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#define FREESTEAM_BUILDING_LIB
#include "region2.h"
#define GAM0(PI,TAU) gam0(PI,TAU)
#define GAM0PI(PI,TAU) (1./PI)
#define GAM0PIPI(PI,TAU) (-1./SQ(PI))
#define GAM0TAU(PI,TAU) gam0tau(TAU)
#define GAM0TAUTAU(PI,TAU) gam0tautau(TAU)
#define GAM0PITAU(PI,TAU) (0)
#define gam(PI,TAU) (GAM0(PI,TAU) + gamr(PI,TAU))
#define gampi(PI,TAU) (GAM0PI(PI,TAU) + gamrpi(PI,TAU))
#define gampipi(PI,TAU) (GAM0PIPI(PI,TAU) + gamrpipi(PI,TAU))
#define gamtau(PI,TAU) (GAM0TAU(PI,TAU) + gamrtau(PI,TAU))
#define gamtautau(PI,TAU) (GAM0TAUTAU(PI,TAU) + gamrtautau(PI,TAU))
#define gampitau(PI,TAU) (GAM0PITAU(PI,TAU) + gamrpitau(PI,TAU))
static double gamr(double pi, double tau);
static double gamrpi(double pi, double tau);
static double gamrpipi(double pi, double tau);
static double gamrtau(double pi, double tau);
static double gamrtautau(double pi, double tau);
static double gamrpitau(double pi, double tau);
static double gam0(double pi, double tau);
static double gam0tau(double tau);
static double gam0tautau(double tau);
#include <math.h>
#include "common.h"
#define R IAPWS97_R
#define REGION2_GPT_PSTAR 1.e6 /* Pa */
#define REGION2_GPT_TSTAR 540. /* K */
#define DEFINE_PITAU(P,T) \
double pi = p / REGION2_GPT_PSTAR; \
double tau = REGION2_GPT_TSTAR / T
double freesteam_region2_v_pT(double p, double T){
DEFINE_PITAU(p,T);
return (R * T / p) * pi * gampi(pi,tau);
}
double freesteam_region2_u_pT(double p, double T){
DEFINE_PITAU(p,T);
return (R * T) * (tau * gamtau(pi,tau) - pi * gampi(pi,tau));
}
double freesteam_region2_s_pT(double p, double T){
DEFINE_PITAU(p,T);
return R * (tau * gamtau(pi,tau) - gam(pi,tau));
}
double freesteam_region2_h_pT(double p, double T){
//fprintf(stderr,"%s: p = %f, T = %f\n",__func__,p,T);
DEFINE_PITAU(p,T);
return R * T * (tau * gamtau(pi,tau));
}
double freesteam_region2_cp_pT(double p, double T){
DEFINE_PITAU(p,T);
return R * (-SQ(tau) * gamtautau(pi,tau));
}
double freesteam_region2_cv_pT(double p, double T){
DEFINE_PITAU(p,T);
return R * (-SQ(tau) * gamtautau(pi,tau) + SQ(gampi(pi,tau) -
tau * gampitau(pi,tau)) / gampipi(pi,tau)
);
}
double freesteam_region2_w_pT(double p, double T){
DEFINE_PITAU(p,T);
double gp = gamrpi(pi,tau);
return sqrt(R * T * (1. + 2.*pi*gp+SQ(pi*gp))/
((1. - SQ(pi)*gamrpipi(pi,tau)) + SQ(1. + pi*gp - tau*pi*gamrpitau(pi,tau))/SQ(tau)/gamtautau(pi,tau))
);
}
double freesteam_region2_g_pT(double p, double T){
DEFINE_PITAU(p,T);
return R * T * gam(pi,tau);
}
double freesteam_region2_a_pT(double p, double T){
DEFINE_PITAU(p,T);
return R * T * (gam(pi,tau) - gampi(pi,tau) * pi);
}
double freesteam_region2_alphav_pT(double p, double T){
DEFINE_PITAU(p,T);
double pigamrpi = pi*gamrpi(pi,tau);
double alphav = 1./T * (1. + pigamrpi - tau*pi*gamrpitau(pi,tau))/(1. + pigamrpi);
//fprintf(stderr,"α_v = %g\n",alphav);
return alphav;
}
double freesteam_region2_kappaT_pT(double p, double T){
DEFINE_PITAU(p,T);
double kappaT = 1./p * (1.-SQ(pi)*gamrpipi(pi,tau)) / (1.+pi*gamrpi(pi,tau));
//fprintf(stderr,"κ_T = %g\n",kappaT);
return kappaT;
}
/*------------------------------------------------------------------------------
REGION 2 IDEAL PART - GAM0(PI,TAU)
*/
typedef struct{
int J;
double n;
} JNData;
const JNData REGION2_GPT_IDEAL_DATA[] = {
{0, -0.96927686500217E+01}
,{1, 0.10086655968018E+02}
,{-5, -0.56087911283020E-02}
,{-4, 0.71452738081455E-01}
,{-3, -0.40710498223928E+00}
,{-2, 0.14240819171444E+01}
,{-1, -0.43839511319450E+01}
,{2, -0.28408632460772E+00}
,{3, 0.21268463753307E-01}
};
const unsigned REGION2_GPT_IDEAL_MAX = sizeof(REGION2_GPT_IDEAL_DATA)/sizeof(JNData);
#define REGION2_GPT_IDEAL_LOOP \
double sum = 0; \
const JNData *d, *e = REGION2_GPT_IDEAL_DATA + REGION2_GPT_IDEAL_MAX; \
for(d = REGION2_GPT_IDEAL_DATA; d < e; ++d)
double gam0(double pi, double tau){
REGION2_GPT_IDEAL_LOOP{
sum += d->n * ipow(tau, d->J);
}
return log(pi) + sum;
}
double gam0tau(double tau){
REGION2_GPT_IDEAL_LOOP{
sum += d->n * d->J * ipow(tau, d->J - 1);
}
return sum;
}
double gam0tautau(double tau){
REGION2_GPT_IDEAL_LOOP{
sum += d->n * d->J * (d->J - 1) * ipow(tau, d->J - 2);
}
return sum;
}
/*------------------------------------------------------------------------------
REGION 2 RESIDUAL PART - GAMR(PI,TAU)
*/
typedef struct{
int I, J;
double n;
} IJNData;
const IJNData REGION2_GPT_RESID_DATA[] = {
{1, 0, -0.17731742473213E-02}
,{1, 1, -0.17834862292358E-01}
,{1, 2, -0.45996013696365E-01}
,{1, 3, -0.57581259083432E-01}
,{1, 6, -0.50325278727930E-01}
,{2, 1, -0.33032641670203E-04}
,{2, 2, -0.18948987516315E-03}
,{2, 4, -0.39392777243355E-02}
,{2, 7, -0.43797295650573E-01}
,{2, 36, -0.26674547914087E-04}
,{3, 0, 0.20481737692309E-07}
,{3, 1, 0.43870667284435E-06}
,{3, 3, -0.32277677238570E-04}
,{3, 6, -0.15033924542148E-02}
,{3, 35, -0.40668253562649E-01}
,{4, 1, -0.78847309559367E-09}
,{4, 2, 0.12790717852285E-07}
,{4, 3, 0.48225372718507E-06}
,{5, 7, 0.22922076337661E-05}
,{6, 3, -0.16714766451061E-10}
,{6, 16, -0.21171472321355E-02}
,{6, 35, -0.23895741934104E+02}
,{7, 0, -0.59059564324270E-17}
,{7, 11, -0.12621808899101E-05}
,{7, 25, -0.38946842435739E-01}
,{8, 8, 0.11256211360459E-10}
,{8, 36, -0.82311340897998E+01}
,{9, 13, 0.19809712802088E-07}
,{10, 4, 0.10406965210174E-18}
,{10, 10, -0.10234747095929E-12}
,{10, 14, -0.10018179379511E-08}
,{16, 29, -0.80882908646985E-10}
,{16, 50, 0.10693031879409E+00}
,{18, 57, -0.33662250574171E+00}
,{20, 20, 0.89185845355421E-24}
,{20, 35, 0.30629316876232E-12}
,{20, 48, -0.42002467698208E-05}
,{21, 21, -0.59056029685639E-25}
,{22, 53, 0.37826947613457E-05}
,{23, 39, -0.12768608934681E-14}
,{24, 26, 0.73087610595061E-28}
,{24, 40, 0.55414715350778E-16}
,{24, 58, -0.94369707241210E-06}
};
const unsigned REGION2_GPT_RESID_MAX = sizeof(REGION2_GPT_RESID_DATA)/sizeof(IJNData);
#define REGION2_GPT_RESID_LOOP \
double sum = 0; \
const IJNData *d, *e = REGION2_GPT_RESID_DATA + REGION2_GPT_RESID_MAX; \
for(d = REGION2_GPT_RESID_DATA; d < e; ++d)
double gamr(double pi, double tau){
REGION2_GPT_RESID_LOOP{
sum += d->n * ipow(pi,d->I) * ipow(tau - 0.5,d->J);
}
return sum;
}
double gamrpi(double pi, double tau){
REGION2_GPT_RESID_LOOP{
sum += d->n * d->I * ipow(pi,d->I -1) * ipow(tau - 0.5,d->J);
}
return sum;
}
double gamrpipi(double pi, double tau){
REGION2_GPT_RESID_LOOP{
sum += d->n * d->I * (d->I - 1) * ipow(pi, d->I - 2) * ipow(tau - 0.5, d->J);
}
return sum;
}
double gamrtau(double pi, double tau){
REGION2_GPT_RESID_LOOP{
sum += d->n * ipow(pi, d->I) * d->J * ipow(tau - 0.5, d->J - 1);
}
return sum;
}
double gamrtautau(double pi, double tau){
REGION2_GPT_RESID_LOOP{
sum += d->n * ipow(pi, d->I) * d->J * (d->J - 1) * ipow(tau - 0.5, d->J - 2);
}
return sum;
}
double gamrpitau(double pi, double tau){
REGION2_GPT_RESID_LOOP{
sum += d->n * d->I * ipow(pi, d->I - 1) * d->J * ipow(tau - 0.5, d->J - 1);
}
return sum;
}

View file

@ -0,0 +1,42 @@
/*
freesteam - IAPWS-IF97 steam tables library
Copyright (C) 2004-2009 John Pye
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef FREESTEAM_REGION2_H
#define FREESTEAM_REGION2_H
#include "common.h"
#define REGION2_TMAX 1073.15
FREESTEAM_DLL double freesteam_region2_v_pT(double p, double T);
FREESTEAM_DLL double freesteam_region2_u_pT(double p, double T);
FREESTEAM_DLL double freesteam_region2_s_pT(double p, double T);
FREESTEAM_DLL double freesteam_region2_h_pT(double p, double T);
FREESTEAM_DLL double freesteam_region2_cp_pT(double p, double T);
FREESTEAM_DLL double freesteam_region2_cv_pT(double p, double T);
FREESTEAM_DLL double freesteam_region2_w_pT(double p, double T);
FREESTEAM_DLL double freesteam_region2_a_pT(double p, double T);
FREESTEAM_DLL double freesteam_region2_g_pT(double p, double T);
/* used in calculations of derivatives, see derivs.c */
double freesteam_region2_alphav_pT(double p, double T);
double freesteam_region2_kappaT_pT(double p, double T);
#endif

View file

@ -0,0 +1,197 @@
/*
freesteam - IAPWS-IF97 steam tables library
Copyright (C) 2004-2009 John Pye
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#define FREESTEAM_BUILDING_LIB
#include "region3.h"
const double REGION3_ARHOT_TSTAR = 647.096 /* K */;
const double REGION3_ARHOT_RHOSTAR = 322. /* K */;
#define DEFINE_DELTAU(RHO,T) \
double del = rho / REGION3_ARHOT_RHOSTAR; \
double tau = REGION3_ARHOT_TSTAR / T
#define R 461.526
static double phi(double del, double tau);
static double phidel(double del, double tau);
static double phideldel(double del, double tau);
static double phitau(double del, double tau);
static double phitautau(double del, double tau);
static double phideltau(double del, double tau);
#include <math.h>
double freesteam_region3_p_rhoT(double rho, double T){
DEFINE_DELTAU(rho,T);
return rho * R * T * del * phidel(del,tau);
}
double freesteam_region3_u_rhoT(double rho, double T){
DEFINE_DELTAU(rho,T);
return R * T * tau * phitau(del,tau);
}
double freesteam_region3_s_rhoT(double rho, double T){
DEFINE_DELTAU(rho,T);
return R * (tau * phitau(del,tau) - phi(del,tau));
}
double freesteam_region3_h_rhoT(double rho, double T){
DEFINE_DELTAU(rho,T);
return R * T * (tau * phitau(del,tau) + del * phidel(del,tau));
}
double freesteam_region3_cp_rhoT(double rho, double T){
DEFINE_DELTAU(rho,T);
return R * (
-SQ(tau) * phitautau(del,tau)
+ (
ipow (del * phidel(del,tau) - del * tau * phideltau(del,tau), 2)
/ (2 * del * phidel(del,tau) + SQ(del) * phideldel(del,tau))
)
);
}
double freesteam_region3_cv_rhoT(double rho, double T){
DEFINE_DELTAU(rho,T);
return R * (-SQ(tau) * phitautau(del,tau));
}
double freesteam_region3_w_rhoT(double rho, double T){
DEFINE_DELTAU(rho,T);
return sqrt(R * T * (
2 * del * phidel(del,tau) + SQ(del) * phideldel(del,tau)
- (
ipow (del * phidel(del,tau) - del * tau * phideltau(del,tau), 2)
/ (SQ(tau) * phitautau(del,tau))
)
));
}
double freesteam_region3_alphap_rhoT(double rho, double T){
DEFINE_DELTAU(rho,T);
return 1./T * (1. - tau*phideltau(del,tau)/phidel(del,tau));
}
double freesteam_region3_betap_rhoT(double rho, double T){
DEFINE_DELTAU(rho,T);
return rho*(2. + del * phideldel(del,tau)/phidel(del,tau));
}
/*----------------------------------------------------------------------------*/
typedef struct{
int I, J;
double n;
} IJNData;
const double REGION3_N1 = 0.10658070028513E+01;
const IJNData REGION3_ARHOT_DATA[] = {
{0, 0, -0.15732845290239E+02}
,{0, 1, 0.20944396974307E+02}
,{0, 2, -0.76867707878716E+01}
,{0, 7, 0.26185947787954E+01}
,{0, 10, -0.28080781148620E+01}
,{0, 12, 0.12053369696517E+01}
,{0, 23, -0.84566812812502E-02}
,{1, 2, -0.12654315477714E+01}
,{1, 6, -0.11524407806681E+01}
,{1, 15, 0.88521043984318E+00}
,{1, 17, -0.64207765181607E+00}
,{2, 0, 0.38493460186671E+00}
,{2, 2, -0.85214708824206E+00}
,{2, 6, 0.48972281541877E+01}
,{2, 7, -0.30502617256965E+01}
,{2, 22, 0.39420536879154E-01}
,{2, 26, 0.12558408424308E+00}
,{3, 0, -0.27999329698710E+00}
,{3, 2, 0.13899799569460E+01}
,{3, 4, -0.20189915023570E+01}
,{3, 16, -0.82147637173963E-02}
,{3, 26, -0.47596035734923E+00}
,{4, 0, 0.43984074473500E-01}
,{4, 2, -0.44476435428739E+00}
,{4, 4, 0.90572070719733E+00}
,{4, 26, 0.70522450087967E+00}
,{5, 1, 0.10770512626332E+00}
,{5, 3, -0.32913623258954E+00}
,{5, 26, -0.50871062041158E+00}
,{6, 0, -0.22175400873096E-01}
,{6, 2, 0.94260751665092E-01}
,{6, 26, 0.16436278447961E+00}
,{7, 2, -0.13503372241348E-01}
,{8, 26, -0.14834345352472E-01}
,{9, 2, 0.57922953628084E-03}
,{9, 26, 0.32308904703711E-02}
,{10, 0, 0.80964802996215E-04}
,{10, 1, -0.16557679795037E-03}
,{11, 26, -0.44923899061815E-04}
};
const unsigned REGION3_ARHOT_MAX = sizeof(REGION3_ARHOT_DATA)/sizeof(IJNData);
#define REGION3_ARHOT_LOOP \
double sum = 0; \
const IJNData *d, *e = REGION3_ARHOT_DATA + REGION3_ARHOT_MAX; \
for(d = REGION3_ARHOT_DATA; d < e; ++d)
double phi(double del, double tau){
REGION3_ARHOT_LOOP{
sum += d->n * ipow(del, d->I) * ipow(tau, d->J);
}
return sum + REGION3_N1 * log(del);
}
double phidel(double del, double tau){
REGION3_ARHOT_LOOP{
sum += +d->n * d->I * ipow(del, d->I - 1) * ipow(tau, d->J);
}
return sum + REGION3_N1 / del;
}
double phideldel(double del, double tau){
REGION3_ARHOT_LOOP{
sum += d->n * d->I * (d->I - 1) * ipow(del, d->I - 2) * ipow(tau, d->J);
}
return sum - REGION3_N1 / SQ(del) ;
}
double phitau(double del, double tau){
REGION3_ARHOT_LOOP{
sum += d->n * ipow(del, d->I) * d->J * ipow(tau, d->J - 1);
}
return sum;
}
double phitautau(double del, double tau){
REGION3_ARHOT_LOOP{
sum += d->n * ipow(del, d->I) * d->J * (d->J - 1) * ipow(tau, d->J - 2);
}
return sum;
}
double phideltau(double del, double tau){
REGION3_ARHOT_LOOP{
sum += d->n * d->I * ipow(del, d->I - 1) * d->J * ipow(tau, d->J - 1);
}
return sum;
}

View file

@ -0,0 +1,39 @@
/*
freesteam - IAPWS-IF97 steam tables library
Copyright (C) 2004-2009 John Pye
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef FREESTEAM_REGION3_H
#define FREESTEAM_REGION3_H
#include "common.h"
FREESTEAM_DLL double freesteam_region3_p_rhoT(double rho, double T);
FREESTEAM_DLL double freesteam_region3_u_rhoT(double rho, double T);
FREESTEAM_DLL double freesteam_region3_s_rhoT(double rho, double T);
FREESTEAM_DLL double freesteam_region3_h_rhoT(double rho, double T);
FREESTEAM_DLL double freesteam_region3_cp_rhoT(double rho, double T);
FREESTEAM_DLL double freesteam_region3_cv_rhoT(double rho, double T);
FREESTEAM_DLL double freesteam_region3_w_rhoT(double rho, double T);
/* used in calculations of derivatives, see derivs.c */
double freesteam_region3_alphap_rhoT(double rho, double T);
double freesteam_region3_betap_rhoT(double rho, double T);
#endif

View file

@ -0,0 +1,273 @@
/*
freesteam - IAPWS-IF97 steam tables library
Copyright (C) 2004-2009 John Pye
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#define FREESTEAM_BUILDING_LIB
#include "region4.h"
#include "region1.h"
#include "region3.h"
#include "region2.h"
#include <math.h>
#include <stdlib.h>
const double REGION4_N[11] = { 0, 0.11670521452767E+04, -0.72421316703206E+06
, -0.17073846940092E+02, 0.12020824702470E+05, -0.32325550322333E+07
, 0.14915108613530E+02, -0.48232657361591E+04, 0.40511340542057E+06
, -0.23855557567849E+00, 0.65017534844798E+03
};
#define REGION4_PSTAR 1e6 /* Pa */
#define REGION4_TSTAR 1 /* K */
/*------------------------------------------------------------------------------
REGION 4 SATURATION CURVE psat(T)
*/
double freesteam_region4_psat_T(double T){
//fprintf(stderr,"freesteam_region4_psat_T(T = %f)\n", T );
double ups = T/REGION4_TSTAR + REGION4_N[9] / (T/REGION4_TSTAR - REGION4_N[10]);
double A = SQ(ups) + REGION4_N[1] * ups + REGION4_N[2];
double B = REGION4_N[3] * SQ(ups) + REGION4_N[4] * ups + REGION4_N[5];
double C = REGION4_N[6] * SQ(ups) + REGION4_N[7] * ups + REGION4_N[8];
double expr = 2. * C / (- B + sqrt(SQ(B) - 4. * A * C));
double psat = SQ(SQ(expr)) * REGION4_PSTAR;
/* fprintf(stderr,"freesteam_region4_psat_T = %f MPa\n", psat/1e6);*/
return psat;
}
/*------------------------------------------------------------------------------
REGION 4 SATURATION CURVE Tsat(p) (BACKWARDS EQUATION)
*/
double freesteam_region4_Tsat_p(double p){
IAPWS97_APPROXIMATE;
double beta = pow(p/REGION4_PSTAR, 0.25);
double E = SQ(beta) + REGION4_N[3] * beta + REGION4_N[6];
double F = REGION4_N[1] * SQ(beta) + REGION4_N[4] * beta + REGION4_N[7];
double G = REGION4_N[2] * SQ(beta) + REGION4_N[5] * beta + REGION4_N[8];
double D = 2. * G / (-F - sqrt(SQ(F) - 4. * E * G));
double theta = 0.5 * (REGION4_N[10] + D - sqrt(SQ(REGION4_N[10] + D) - 4.0 * (REGION4_N[9] + REGION4_N[10] * D)));
/* FIXME iterative improve this estimate? is it necessary? */
return theta /* * REGION4_TSTAR = 1 {K} */;
}
/*------------------------------------------------------------------------------
REGION 4 DENSITIES rhof(T), rhog(T) (SUPPLEMENTARY EQUATIONS)
*/
/**
Coefficients for getSatDensWater_T
*/
const double REGION4_B[7]
= { 0, 1.99274064, 1.09965342, -0.510839303, -1.75493479, -45.5170352, -6.74694450E+05 };
/**
Coefficients for getSatDensSteam_T
*/
const double REGION4_C[7]
= { 0, -2.03150240, -2.68302940, -5.38626492, -17.2991605, -44.7586581, -63.9201063 };
double freesteam_region4_rhof_T(double T){
IAPWS97_APPROXIMATE;
double tau = 1 - T / IAPWS97_TCRIT;
double tau_1_3 = pow(tau,1./3);
double tau_2_3 = SQ(tau_1_3);
double tau_5_3 = tau * tau_2_3;
double tau_16_3 = SQ(tau_5_3) * tau_5_3 * tau_1_3;
double tau_43_3 = SQ(tau_16_3) * SQ(tau_5_3) * tau_1_3;
double tau_110_3 = SQ(tau_43_3) * tau_16_3 * tau_5_3 * tau;
double delta = 1
+ REGION4_B[1]*tau_1_3
+ REGION4_B[2]*tau_2_3
+ REGION4_B[3]*tau_5_3
+ REGION4_B[4]*tau_16_3
+ REGION4_B[5]*tau_43_3
+ REGION4_B[6]*tau_110_3;
return delta * IAPWS97_RHOCRIT;
/* FIXME iteratively improve vf estimate */
}
double freesteam_region4_rhog_T(double T){
IAPWS97_APPROXIMATE;
double tau = 1. - T / IAPWS97_TCRIT;
double tau_1_6 = pow(tau,1.0/6);
double tau_2_6 = SQ(tau_1_6);
double tau_4_6 = SQ(tau_2_6);
double tau_8_6 = SQ(tau_4_6);
double tau_16_6 = SQ(tau_8_6);
double tau_18_6 = tau_16_6 * tau_2_6;
double tau_37_6 = SQ(tau_18_6) * tau_1_6;
double tau_71_6 = tau_37_6 * tau_18_6 * tau_16_6;
double ln_delta =
REGION4_C[1]*tau_2_6
+ REGION4_C[2]*tau_4_6
+ REGION4_C[3]*tau_8_6
+ REGION4_C[4]*tau_18_6
+ REGION4_C[5]*tau_37_6
+ REGION4_C[6]*tau_71_6;
return exp(ln_delta) * IAPWS97_RHOCRIT;
/* FIXME iteratively improve vg estimate */
}
/*------------------------------------------------------------------------------
INTERPOLATIONS FOR PROPERTIES WITHIN REGION 4
*/
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);
}
double freesteam_region4_u_Tx(double T, double x){
double uf, ug;
if(T < REGION1_TMAX){
double psat = freesteam_region4_psat_T(T);
uf = freesteam_region1_u_pT(psat,T);
ug = freesteam_region2_u_pT(psat,T);
}else{
double rhof, rhog;
rhof = freesteam_region4_rhof_T(T);
rhog = freesteam_region4_rhog_T(T);
uf = freesteam_region3_u_rhoT(rhof,T);
ug = freesteam_region3_u_rhoT(rhog,T);
}
return uf + x*(ug - uf);
}
double freesteam_region4_h_Tx(double T, double x){
double hf, hg;
if(T < REGION1_TMAX){
double psat = freesteam_region4_psat_T(T);
hf = freesteam_region1_h_pT(psat,T);
hg = freesteam_region2_h_pT(psat,T);
//fprintf(stderr,"%s: T = %f K, psat = %f MPa, hf = %f kJ/kg, hg = %f kJ/kg\n",__func__,T,psat/1e6,hf/1e3,hg);
}else{
double rhof, rhog;
rhof = freesteam_region4_rhof_T(T);
rhog = freesteam_region4_rhog_T(T);
hf = freesteam_region3_h_rhoT(rhof,T);
hg = freesteam_region3_h_rhoT(rhog,T);
}
return hf + x*(hg - hf);
}
double freesteam_region4_s_Tx(double T, double x){
double sf, sg;
if(T < REGION1_TMAX){
double psat = freesteam_region4_psat_T(T);
sf = freesteam_region1_s_pT(psat,T);
sg = freesteam_region2_s_pT(psat,T);
}else{
double rhof, rhog;
rhof = freesteam_region4_rhof_T(T);
rhog = freesteam_region4_rhog_T(T);
sf = freesteam_region3_s_rhoT(rhof,T);
sg = freesteam_region3_s_rhoT(rhog,T);
}
return sf + x*(sg - sf);
}
double freesteam_region4_cp_Tx(double T, double x){
double cpf, cpg;
if(T < REGION1_TMAX){
double psat = freesteam_region4_psat_T(T);
cpf = freesteam_region1_cp_pT(psat,T);
cpg = freesteam_region2_cp_pT(psat,T);
}else{
double rhof, rhog;
rhof = freesteam_region4_rhof_T(T);
rhog = freesteam_region4_rhog_T(T);
cpf = freesteam_region3_cp_rhoT(rhof,T);
cpg = freesteam_region3_cp_rhoT(rhog,T);
}
return cpf + x*(cpg - cpf);
}
double freesteam_region4_cv_Tx(double T, double x){
double cvf, cvg;
if(T < REGION1_TMAX){
double psat = freesteam_region4_psat_T(T);
cvf = freesteam_region1_cv_pT(psat,T);
cvg = freesteam_region2_cv_pT(psat,T);
}else{
double rhof, rhog;
rhof = freesteam_region4_rhof_T(T);
rhog = freesteam_region4_rhog_T(T);
cvf = freesteam_region3_cv_rhoT(rhof,T);
cvg = freesteam_region3_cv_rhoT(rhog,T);
}
return cvf + x*(cvg - cvf);
}
/*------------------------------------------------------------------------------
*/
double freesteam_region4_dpsatdT_T(double T){
/* calculated this derivative using implicit differentiation of the
quadratic expression, then derivatives of beta and script-theta */
double beta = pow(freesteam_region4_psat_T(T)/REGION4_PSTAR, 0.25);
#define N REGION4_N
double theta = T/REGION4_TSTAR + N[9] / (T/REGION4_TSTAR - N[10]);
double XBETA = (2.*beta + N[3])*SQ(theta) + (2.*beta*N[1] + N[4])*theta + 2.*N[2]*beta + N[5];
double XTHETA = (2.*theta + N[1])*SQ(beta) + (2.*N[3]*theta + N[4])*beta + 2.*N[6]*theta + N[7];
double dthetadT = (1 - N[9] / (T/REGION4_TSTAR - N[10]))/REGION4_TSTAR;
double dbetadtheta = -XTHETA/XBETA;
double dpdbeta = 4*SQ(beta)*beta*REGION4_PSTAR;
#undef N
return dpdbeta * dbetadtheta * dthetadT;
}

View file

@ -0,0 +1,41 @@
/*
freesteam - IAPWS-IF97 steam tables library
Copyright (C) 2004-2009 John Pye
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef FREESTEAM_REGION4_H
#define FREESTEAM_REGION4_H
#include "common.h"
FREESTEAM_DLL double freesteam_region4_psat_T(double T);
FREESTEAM_DLL double freesteam_region4_Tsat_p(double p);
FREESTEAM_DLL double freesteam_region4_rhof_T(double T);
FREESTEAM_DLL double freesteam_region4_rhog_T(double T);
FREESTEAM_DLL double freesteam_region4_v_Tx(double T, double x);
FREESTEAM_DLL double freesteam_region4_u_Tx(double T, double x);
FREESTEAM_DLL double freesteam_region4_h_Tx(double T, double x);
FREESTEAM_DLL double freesteam_region4_s_Tx(double T, double x);
FREESTEAM_DLL double freesteam_region4_cp_Tx(double T, double x);
FREESTEAM_DLL double freesteam_region4_cv_Tx(double T, double x);
FREESTEAM_DLL double freesteam_region4_dpsatdT_T(double T);
#endif

View file

@ -0,0 +1,427 @@
/*
freesteam - IAPWS-IF97 steam tables library
Copyright (C) 2004-2009 John Pye
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#define FREESTEAM_BUILDING_LIB
#include "solver2.h"
#include "region1.h"
#include "region2.h"
#include "region3.h"
#include "region4.h"
#include "b23.h"
#include "derivs.h"
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <gsl/gsl_multiroots.h>
/*------------------------------------------------------------------------------
LOOKUP FOR APPROPRIATE PROPERTY EVALUATION FUNCTION
*/
typedef double PropertyFunction(double, double);
static PropertyFunction *solver2_region3_propfn(FREESTEAM_CHAR A){
switch(A){
case 'p': return &freesteam_region3_p_rhoT;
case 'u': return &freesteam_region3_u_rhoT;
case 's': return &freesteam_region3_s_rhoT;
case 'h': return &freesteam_region3_h_rhoT;
default: return 0;
}
}
/* this function is a needed bit of a redundancy with solver2 in region 4 */
static double solver2_region4_p_Tx(double T, double x){
(void)x;
return freesteam_region4_psat_T(T);
}
static PropertyFunction *solver2_region4_propfn(FREESTEAM_CHAR A){
switch(A){
case 'p': return &solver2_region4_p_Tx;
case 'u': return &freesteam_region4_u_Tx;
case 's': return &freesteam_region4_s_Tx;
case 'h': return &freesteam_region4_h_Tx;
case 'v': return &freesteam_region4_v_Tx;
default: return 0;
}
}
/* completely unnecessary... */
static double solver2_region2_p_pT(double p, double T){
(void)T;
return p;
}
static PropertyFunction *solver2_region2_propfn(FREESTEAM_CHAR A){
switch(A){
case 'p': return &solver2_region2_p_pT;
case 'u': return &freesteam_region2_u_pT;
case 's': return &freesteam_region2_s_pT;
case 'h': return &freesteam_region2_h_pT;
case 'v': return &freesteam_region2_v_pT;
default: return 0;
}
}
/* completely unnecessary... */
static double solver2_region1_p_pT(double p, double T){
(void)T;
return p;
}
static PropertyFunction *solver2_region1_propfn(FREESTEAM_CHAR A){
switch(A){
case 'p': return &solver2_region1_p_pT;
case 'u': return &freesteam_region1_u_pT;
case 's': return &freesteam_region1_s_pT;
case 'h': return &freesteam_region1_h_pT;
case 'v': return &freesteam_region1_v_pT;
default: return 0;
}
}
typedef struct{
FREESTEAM_CHAR A,B;
PropertyFunction *Afn, *Bfn;
double a,b;
} Solver2Data;
/*------------------------------------------------------------------------------
REGION 3
*/
static int region3_f(const gsl_vector *x, void *user_data, gsl_vector *f){
#define D ((Solver2Data *)user_data)
double rho = gsl_vector_get(x,0);
double T = gsl_vector_get(x,1);
gsl_vector_set(f, 0, (*(D->Afn))(rho,T) - (D->a));
gsl_vector_set(f, 1, (*(D->Bfn))(rho,T) - (D->b));
return GSL_SUCCESS;
#undef D
}
static int region3_df(const gsl_vector *x, void *user_data, gsl_matrix *J){
#define D ((Solver2Data *)user_data)
double rho = gsl_vector_get(x,0);
double T = gsl_vector_get(x,1);
SteamState S = freesteam_region3_set_rhoT(rho,T);
gsl_matrix_set(J, 0, 0, -1./SQ(rho)*freesteam_region3_dAdvT(D->A,S));
gsl_matrix_set(J, 0, 1, freesteam_region3_dAdTv(D->A,S));
gsl_matrix_set(J, 1, 0, -1./SQ(rho)*freesteam_region3_dAdvT(D->B,S));
gsl_matrix_set(J, 1, 1, freesteam_region3_dAdTv(D->B,S));
return GSL_SUCCESS;
#undef D
}
static int region3_fdf(const gsl_vector *x, void *user_data, gsl_vector *f, gsl_matrix *J){
return region3_f(x, user_data, f) || region3_df(x, user_data, J);
}
#if 0
static void region3_print_state(size_t iter, gsl_multiroot_fdfsolver *s){
double rho = gsl_vector_get(s->x,0);
double T = gsl_vector_get(s->x,1);
fprintf(stderr,"iter = %lu: rho = %g, T = %g\n", iter,rho,T);
}
#endif
SteamState freesteam_solver2_region3(FREESTEAM_CHAR A, FREESTEAM_CHAR B, double atarget, double btarget, SteamState guess, int *retstatus){
const gsl_multiroot_fdfsolver_type *T;
gsl_multiroot_fdfsolver *s;
int status;
size_t iter = 0;
const size_t n = 2;
Solver2Data D = {A,B,solver2_region3_propfn(A), solver2_region3_propfn(B), atarget,btarget};
gsl_multiroot_function_fdf f = {&region3_f, &region3_df, &region3_fdf, n, &D};
gsl_vector *x = gsl_vector_alloc(n);
gsl_vector_set(x, 0, freesteam_rho(guess));
gsl_vector_set(x, 1, freesteam_T(guess));
T = gsl_multiroot_fdfsolver_gnewton;
s = gsl_multiroot_fdfsolver_alloc(T, n);
gsl_multiroot_fdfsolver_set(s, &f, x);
//region3_print_state(iter, s);
do{
iter++;
status = gsl_multiroot_fdfsolver_iterate(s);
//region3_print_state(iter, s);
if(status){
/* check if solver is stuck */
break;
}
status = gsl_multiroot_test_residual(s->f, 2e-6);
} while(status == GSL_CONTINUE && iter < 50);
SteamState S = freesteam_region3_set_rhoT(gsl_vector_get(s->x,0), gsl_vector_get(s->x,1));
gsl_multiroot_fdfsolver_free(s);
gsl_vector_free(x);
*retstatus = status;
if(status)fprintf(stderr,"%s (%s:%d): %s: ",__func__,__FILE__,__LINE__,gsl_strerror(status));
//freesteam_fprint(stderr,S);
return S;
}
/*------------------------------------------------------------------------------
REGION 4
*/
static int region4_f(const gsl_vector *X, void *user_data, gsl_vector *f){
#define D ((Solver2Data *)user_data)
double T = gsl_vector_get(X,0);
double x = gsl_vector_get(X,1);
gsl_vector_set(f, 0, (*(D->Afn))(T,x) - (D->a));
gsl_vector_set(f, 1, (*(D->Bfn))(T,x) - (D->b));
return GSL_SUCCESS;
#undef D
}
static int region4_df(const gsl_vector *x, void *user_data, gsl_matrix *J){
#define D ((Solver2Data *)user_data)
SteamState S = freesteam_region4_set_Tx(gsl_vector_get(x,0),gsl_vector_get(x,1));
gsl_matrix_set(J, 0, 0, freesteam_region4_dAdTx(D->A,S));
gsl_matrix_set(J, 0, 1, freesteam_region4_dAdxT(D->A,S));
gsl_matrix_set(J, 1, 0, freesteam_region4_dAdTx(D->B,S));
gsl_matrix_set(J, 1, 1, freesteam_region4_dAdxT(D->B,S));
return GSL_SUCCESS;
#undef D
}
static int region4_fdf(const gsl_vector *x, void *user_data, gsl_vector *f, gsl_matrix *J){
return region4_f(x, user_data, f) || region4_df(x, user_data, J);
}
#if 0
static void region4_print_state(size_t iter, gsl_multiroot_fdfsolver *s){
double T = gsl_vector_get(s->x,0);
double x = gsl_vector_get(s->x,1);
fprintf(stderr,"iter = %lu: T = %g, x = %g\n", iter,T,x);
}
#endif
SteamState freesteam_solver2_region4(FREESTEAM_CHAR A, FREESTEAM_CHAR B, double atarget, double btarget, SteamState guess, int *retstatus){
const gsl_multiroot_fdfsolver_type *T;
gsl_multiroot_fdfsolver *s;
int status;
size_t iter = 0;
const size_t n = 2;
Solver2Data D = {A,B,solver2_region4_propfn(A), solver2_region4_propfn(B), atarget,btarget};
gsl_multiroot_function_fdf f = {&region4_f, &region4_df, &region4_fdf, n, &D};
gsl_vector *x = gsl_vector_alloc(n);
assert(guess.region==4);
gsl_vector_set(x, 0, guess.R4.T);
gsl_vector_set(x, 1, guess.R4.x);
T = gsl_multiroot_fdfsolver_gnewton;
s = gsl_multiroot_fdfsolver_alloc(T, n);
gsl_multiroot_fdfsolver_set(s, &f, x);
//region4_print_state(iter, s);
do{
iter++;
status = gsl_multiroot_fdfsolver_iterate(s);
//region4_print_state(iter, s);
if(status){
/* check if solver is stuck */
break;
}
status = gsl_multiroot_test_residual(s->f, 1e-7);
} while(status == GSL_CONTINUE && iter < 20);
fprintf(stderr,"status = %s\n", gsl_strerror (status));
SteamState S = freesteam_region4_set_Tx(gsl_vector_get(s->x,0), gsl_vector_get(s->x,1));
gsl_multiroot_fdfsolver_free(s);
gsl_vector_free(x);
*retstatus = status;
if(status)fprintf(stderr,"%s (%s:%d): %s: ",__func__,__FILE__,__LINE__,gsl_strerror(status));
//freesteam_fprint(stderr,S);
return S;
}
/*------------------------------------------------------------------------------
REGION 2
*/
static int region2_f(const gsl_vector *x, void *user_data, gsl_vector *f){
#define D ((Solver2Data *)user_data)
double p = gsl_vector_get(x,0);
double T = gsl_vector_get(x,1);
gsl_vector_set(f, 0, (*(D->Afn))(p,T) - (D->a));
gsl_vector_set(f, 1, (*(D->Bfn))(p,T) - (D->b));
return GSL_SUCCESS;
#undef D
}
static int region2_df(const gsl_vector *x, void *user_data, gsl_matrix *J){
#define D ((Solver2Data *)user_data)
double p = gsl_vector_get(x,0);
double T = gsl_vector_get(x,1);
SteamState S = freesteam_region2_set_pT(p,T);
gsl_matrix_set(J, 0, 0, freesteam_region2_dAdpT(D->A,S));
gsl_matrix_set(J, 0, 1, freesteam_region2_dAdTp(D->A,S));
gsl_matrix_set(J, 1, 0, freesteam_region2_dAdpT(D->B,S));
gsl_matrix_set(J, 1, 1, freesteam_region2_dAdTp(D->B,S));
return GSL_SUCCESS;
#undef D
}
static int region2_fdf(const gsl_vector *x, void *user_data, gsl_vector *f, gsl_matrix *J){
return region2_f(x, user_data, f) || region2_df(x, user_data, J);
}
static void region2_print_state(size_t iter, gsl_multiroot_fdfsolver *s){
double p = gsl_vector_get(s->x,0);
double T = gsl_vector_get(s->x,1);
fprintf(stderr,"iter = %lu: p = %g, T = %g\n", (long unsigned)iter,p,T);
}
SteamState freesteam_solver2_region2(FREESTEAM_CHAR A, FREESTEAM_CHAR B, double atarget, double btarget, SteamState guess, int *retstatus){
const gsl_multiroot_fdfsolver_type *T;
gsl_multiroot_fdfsolver *s;
int status;
size_t iter = 0;
const size_t n = 2;
fprintf(stderr,"region 2 solver...\n");
Solver2Data D = {A,B,solver2_region2_propfn(A), solver2_region2_propfn(B), atarget,btarget};
gsl_multiroot_function_fdf f = {&region2_f, &region2_df, &region2_fdf, n, &D};
gsl_vector *x = gsl_vector_alloc(n);
gsl_vector_set(x, 0, freesteam_rho(guess));
gsl_vector_set(x, 1, freesteam_T(guess));
T = gsl_multiroot_fdfsolver_gnewton;
s = gsl_multiroot_fdfsolver_alloc(T, n);
gsl_multiroot_fdfsolver_set(s, &f, x);
region2_print_state(iter, s);
do{
iter++;
status = gsl_multiroot_fdfsolver_iterate(s);
region2_print_state(iter, s);
if(status){
/* check if solver is stuck */
break;
}
status = gsl_multiroot_test_residual(s->f, 1e-7);
} while(status == GSL_CONTINUE && iter < 20);
SteamState S = freesteam_region2_set_pT(gsl_vector_get(s->x,0), gsl_vector_get(s->x,1));
gsl_multiroot_fdfsolver_free(s);
gsl_vector_free(x);
*retstatus = status;
if(status)fprintf(stderr,"%s (%s:%d): %s: ",__func__,__FILE__,__LINE__,gsl_strerror(status));
//freesteam_fprint(stderr,S);
return S;
}
/*------------------------------------------------------------------------------
REGION 1
*/
static int region1_f(const gsl_vector *x, void *user_data, gsl_vector *f){
#define D ((Solver2Data *)user_data)
double p = gsl_vector_get(x,0);
double T = gsl_vector_get(x,1);
gsl_vector_set(f, 0, (*(D->Afn))(p,T) - (D->a));
gsl_vector_set(f, 1, (*(D->Bfn))(p,T) - (D->b));
return GSL_SUCCESS;
#undef D
}
static int region1_df(const gsl_vector *x, void *user_data, gsl_matrix *J){
#define D ((Solver2Data *)user_data)
double p = gsl_vector_get(x,0);
double T = gsl_vector_get(x,1);
SteamState S = freesteam_region1_set_pT(p,T);
gsl_matrix_set(J, 0, 0, freesteam_region1_dAdpT(D->A,S));
gsl_matrix_set(J, 0, 1, freesteam_region1_dAdTp(D->A,S));
gsl_matrix_set(J, 1, 0, freesteam_region1_dAdpT(D->B,S));
gsl_matrix_set(J, 1, 1, freesteam_region1_dAdTp(D->B,S));
return GSL_SUCCESS;
#undef D
}
static int region1_fdf(const gsl_vector *x, void *user_data, gsl_vector *f, gsl_matrix *J){
return region1_f(x, user_data, f) || region1_df(x, user_data, J);
}
#if 0
static void region1_print_state(size_t iter, gsl_multiroot_fdfsolver *s){
double p = gsl_vector_get(s->x,0);
double T = gsl_vector_get(s->x,1);
fprintf(stderr,"iter = %lu: p = %g, T = %g\n", iter,p,T);
}
#endif
SteamState freesteam_solver2_region1(FREESTEAM_CHAR A, FREESTEAM_CHAR B, double atarget, double btarget, SteamState guess, int *retstatus){
const gsl_multiroot_fdfsolver_type *T;
gsl_multiroot_fdfsolver *s;
int status;
size_t iter = 0;
const size_t n = 2;
//fprintf(stderr,"region 1 solver...\n");
Solver2Data D = {A,B,solver2_region1_propfn(A), solver2_region1_propfn(B), atarget,btarget};
gsl_multiroot_function_fdf f = {&region1_f, &region1_df, &region1_fdf, n, &D};
gsl_vector *x = gsl_vector_alloc(n);
gsl_vector_set(x, 0, freesteam_rho(guess));
gsl_vector_set(x, 1, freesteam_T(guess));
T = gsl_multiroot_fdfsolver_gnewton;
s = gsl_multiroot_fdfsolver_alloc(T, n);
gsl_multiroot_fdfsolver_set(s, &f, x);
//region1_print_state(iter, s);
do{
iter++;
status = gsl_multiroot_fdfsolver_iterate(s);
//region1_print_state(iter, s);
if(status){
/* check if solver is stuck */
break;
}
status = gsl_multiroot_test_residual(s->f, 1e-6);
} while(status == GSL_CONTINUE && iter < 20);
SteamState S = freesteam_region1_set_pT(gsl_vector_get(s->x,0), gsl_vector_get(s->x,1));
gsl_multiroot_fdfsolver_free(s);
gsl_vector_free(x);
*retstatus = status;
if(status){
fprintf(stderr,"%s (%s:%d): %s: ",__func__,__FILE__,__LINE__,gsl_strerror(status));
freesteam_fprint(stderr,S);
}
return S;
}

View file

@ -0,0 +1,61 @@
/*
freesteam - IAPWS-IF97 steam tables library
Copyright (C) 2004-2009 John Pye
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef FREESTEAM_SOLVER2_H
#define FREESTEAM_SOLVER2_H
#include "common.h"
#include "steam.h"
/*
two-way solver interface, for unusual property pairs that are not
implemented in official IAPWS releases.
this solver will use provided 'first guess' estimates, meaning that
if correlations, even approximate, can be provided, then this will
decrease unneeded iteration.
these solvers first require that you know which region you're in.
This is because the correlation variables are different for the different
regions.
'freesteam_region_XX functions will calculate the region for you; but
these need to be hand-coded at this stage.
*/
/**
Two-variable Newton solver for Region 3, using finite difference
approximations for derivatives. The names of the provided variables are
given as X and Y (eg 'T' and 's') then the require state values are given
as x and y (eg 300 and 5500). The solver will attempt to find a state
that satisfies the provided input, and return it as output.
On return, the variable status will be set to 0 on success, or an error code
if something has gone wrong, eg failed to converge.
A first guess must be provided via the 'guess' parameter.
FIXME provide 'default' guess functions.
*/
FREESTEAM_DLL SteamState freesteam_solver2_region1(FREESTEAM_CHAR X, FREESTEAM_CHAR Y, double x, double y, SteamState guess, int *status);
FREESTEAM_DLL SteamState freesteam_solver2_region2(FREESTEAM_CHAR X, FREESTEAM_CHAR Y, double x, double y, SteamState guess, int *status);
FREESTEAM_DLL SteamState freesteam_solver2_region3(FREESTEAM_CHAR X, FREESTEAM_CHAR Y, double x, double y, SteamState guess, int *status);
FREESTEAM_DLL SteamState freesteam_solver2_region4(FREESTEAM_CHAR X, FREESTEAM_CHAR Y, double x, double y, SteamState guess, int *status);
#endif

View file

@ -0,0 +1,320 @@
/*
freesteam - IAPWS-IF97 steam tables library
Copyright (C) 2004-2009 John Pye
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#define FREESTEAM_BUILDING_LIB
#include "steam.h"
#include <stdlib.h>
#include <stdio.h>
#include "region1.h"
#include "region2.h"
#include "region3.h"
#include "region4.h"
#include "b23.h"
#include "backwards.h"
#include "viscosity.h"
#include "thcond.h"
/* 'setter' functions for SteamState (forwards equations) */
SteamState freesteam_region1_set_pT(double p, double T){
SteamState S;
S.region = 1;
S.R1.p = p;
S.R1.T = T;
/* FIXME add bounds check? */
return S;
}
SteamState freesteam_region2_set_pT(double p, double T){
SteamState S;
S.region = 2;
S.R2.p = p;
S.R2.T = T;
/* FIXME add bounds check? */
return S;
}
SteamState freesteam_region3_set_rhoT(double rho, double T){
SteamState S;
S.region = 3;
S.R3.rho = rho;
S.R3.T = T;
/* FIXME add bounds check? */
return S;
}
SteamState freesteam_region4_set_Tx(double T, double x){
SteamState S;
S.region = 4;
S.R4.T = T;
S.R4.x = x;
/* FIXME add bounds check? */
return S;
}
int freesteam_fprint(FILE *f, SteamState S){
int n = 0;
n += fprintf(f, "region %d: ", S.region);
switch(S.region){
case 1:
n += fprintf(f, "p = %f MPa, T = %f K\n", S.R1.p/1e6, S.R1.T);
break;
case 2:
n += fprintf(f, "p = %f MPa, T = %f K\n", S.R2.p/1e6, S.R2.T);
break;
case 3:
n += fprintf(f, "rho = %f kg/m³, T = %f K\n", S.R3.rho, S.R1.T);
break;
case 4:
n += fprintf(f, "T = %f, x = %f\n", S.R4.T, S.R4.x);
break;
}
return n;
}
/* 'getter' functions for SteamState */
int freesteam_region(SteamState S){
return (int)S.region;
}
double freesteam_T(SteamState S){
switch(S.region){
case 1:
return S.R1.T;
case 2:
return S.R2.T;
case 3:
return S.R3.T;
case 4:
return S.R4.T;
default:
fprintf(stderr,"ERROR: invalid region in freesteam_T\n");
exit(1);
}
}
double freesteam_p(SteamState S){
switch(S.region){
case 1:
return S.R1.p;
case 2:
return S.R2.p;
case 3:
return freesteam_region3_p_rhoT(S.R3.rho, S.R3.T);
case 4:
return freesteam_region4_psat_T(S.R4.T);
default:
fprintf(stderr,"ERROR: invalid region in freesteam_p\n");
exit(1);
}
}
double freesteam_v(SteamState S){
switch(S.region){
case 1:
return freesteam_region1_v_pT(S.R1.p,S.R1.T);
case 2:
return freesteam_region2_v_pT(S.R2.p,S.R2.T);
case 3:
return 1./S.R3.rho;
case 4:
return freesteam_region4_v_Tx(S.R4.T, S.R4.x);
default:
fprintf(stderr,"ERROR: invalid region in freesteam_v\n");
exit(1);
}
}
double freesteam_rho(SteamState S){
switch(S.region){
case 1:
return 1./freesteam_region1_v_pT(S.R1.p,S.R1.T);
case 2:
return 1./freesteam_region2_v_pT(S.R2.p,S.R2.T);
case 3:
return S.R3.rho;
case 4:
return 1./freesteam_region4_v_Tx(S.R4.T, S.R4.x);
default:
fprintf(stderr,"ERROR: invalid region in freesteam_rho\n");
exit(1);
}
}
double freesteam_u(SteamState S){
switch(S.region){
case 1:
return freesteam_region1_u_pT(S.R1.p, S.R1.T);
case 2:
return freesteam_region2_u_pT(S.R2.p, S.R2.T);
case 3:
return freesteam_region3_u_rhoT(S.R3.rho,S.R3.T);
case 4:
return freesteam_region4_u_Tx(S.R4.T, S.R4.x);
default:
fprintf(stderr,"ERROR: invalid region in freesteam_u\n");
exit(1);
}
}
double freesteam_h(SteamState S){
switch(S.region){
case 1:
return freesteam_region1_h_pT(S.R1.p, S.R1.T);
case 2:
return freesteam_region2_h_pT(S.R2.p, S.R2.T);
case 3:
return freesteam_region3_h_rhoT(S.R3.rho,S.R3.T);
case 4:
return freesteam_region4_h_Tx(S.R4.T, S.R4.x);
default:
fprintf(stderr,"ERROR: invalid region in freesteam_h\n");
exit(1);
}
}
double freesteam_s(SteamState S){
switch(S.region){
case 1:
return freesteam_region1_s_pT(S.R1.p, S.R1.T);
case 2:
return freesteam_region2_s_pT(S.R2.p, S.R2.T);
case 3:
return freesteam_region3_s_rhoT(S.R3.rho,S.R3.T);
case 4:
return freesteam_region4_s_Tx(S.R4.T, S.R4.x);
default:
fprintf(stderr,"ERROR: invalid region in freesteam_s\n");
exit(1);
}
}
double freesteam_cp(SteamState S){
switch(S.region){
case 1:
return freesteam_region1_cp_pT(S.R1.p, S.R1.T);
case 2:
return freesteam_region2_cp_pT(S.R2.p, S.R2.T);
case 3:
return freesteam_region3_cp_rhoT(S.R3.rho,S.R3.T);
case 4:
return freesteam_region4_cp_Tx(S.R4.T, S.R4.x);
default:
fprintf(stderr,"ERROR: invalid region in freesteam_cp\n");
exit(1);
}
}
double freesteam_cv(SteamState S){
switch(S.region){
case 1:
return freesteam_region1_cv_pT(S.R1.p, S.R1.T);
case 2:
return freesteam_region2_cv_pT(S.R2.p, S.R2.T);
case 3:
return freesteam_region3_cv_rhoT(S.R3.rho,S.R3.T);
case 4:
return freesteam_region4_cv_Tx(S.R4.T, S.R4.x);
default:
fprintf(stderr,"ERROR: invalid region in freesteam_cv\n");
exit(1);
}
}
double freesteam_w(SteamState S){
switch(S.region){
case 1:
return freesteam_region1_w_pT(S.R1.p, S.R1.T);
case 2:
return freesteam_region2_w_pT(S.R2.p, S.R2.T);
case 3:
return freesteam_region3_w_rhoT(S.R3.rho,S.R3.T);
#if 0
case 4:
return freesteam_region4_w_Tx(S.R4.T, S.R4.x);
#endif
default:
fprintf(stderr,"ERROR: invalid region '%d' in freesteam_w\n",S.region);
exit(1);
}
}
double freesteam_x(SteamState S){
switch(S.region){
case 1:
return 0.;
case 2:
return 1.;
case 3:
if(S.R3.rho > IAPWS97_RHOCRIT)return 0.;
return 1.;
case 4:
return S.R4.x;
default:
fprintf(stderr,"ERROR: invalid region '%d' in freesteam_x\n",S.region);
exit(1);
}
}
double freesteam_mu(SteamState S){
static char warned = 0;
switch(S.region){
case 1:
return freesteam_mu_rhoT(1./freesteam_region1_v_pT(S.R1.p,S.R1.T), S.R1.T);
case 2:
return freesteam_mu_rhoT(1./freesteam_region2_v_pT(S.R2.p,S.R2.T), S.R2.T);
case 3:
return freesteam_mu_rhoT(S.R3.rho, S.R3.T);
case 4:
if(!warned){
fprintf(stderr,"WARNING: viscosity evaluation in region 4 is poorly defined! (this warning is only shown once)\n");
warned = 1;
}
return freesteam_mu_rhoT(1./freesteam_region4_v_Tx(S.R4.T, S.R4.x), S.R4.T);
default:
fprintf(stderr,"ERROR: invalid region '%d' in freesteam_mu\n",S.region);
exit(1);
}
}
double freesteam_k(SteamState S){
static char warned = 0;
switch(S.region){
case 1:
return freesteam_k_rhoT(1./freesteam_region1_v_pT(S.R1.p,S.R1.T), S.R1.T);
case 2:
return freesteam_k_rhoT(1./freesteam_region2_v_pT(S.R2.p,S.R2.T), S.R2.T);
case 3:
return freesteam_k_rhoT(S.R3.rho, S.R3.T);
case 4:
if(!warned){
fprintf(stderr,"WARNING: thermal conductivity evaluation in region 4 is poorly defined! (this warning is only shown once)\n");
warned = 1;
}
return freesteam_k_rhoT(1./freesteam_region4_v_Tx(S.R4.T, S.R4.x), S.R4.T);
default:
fprintf(stderr,"ERROR: invalid region '%d' in freesteam_k\n",S.region);
exit(1);
}
}

View file

@ -0,0 +1,89 @@
/*
freesteam - IAPWS-IF97 steam tables library
Copyright (C) 2004-2005 John Pye
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef FREESTEAM_STEAM_H
#define FREESTEAM_STEAM_H
#include "common.h"
#include <stdio.h>
typedef struct SteamState_R1_struct{
double p, T;
} SteamState_R1;
typedef struct SteamState_R2_struct{
double p, T;
} SteamState_R2;
typedef struct SteamState_R3_struct{
double rho, T;
} SteamState_R3;
typedef struct SteamState_R4_struct{
double T, x;
} SteamState_R4;
typedef struct SteamState_struct{
char region;
union{
SteamState_R1 R1;
SteamState_R2 R2;
SteamState_R3 R3;
SteamState_R4 R4;
};
} SteamState;
FREESTEAM_DLL int freesteam_region(SteamState S);
FREESTEAM_DLL SteamState freesteam_region1_set_pT(double p, double T);
FREESTEAM_DLL SteamState freesteam_region2_set_pT(double p, double T);
FREESTEAM_DLL SteamState freesteam_region3_set_rhoT(double rho, double T);
FREESTEAM_DLL SteamState freesteam_region4_set_Tx(double T, double x);
FREESTEAM_DLL int freesteam_fprint(FILE *f, SteamState S);
#if 0
# define FREESTEAM_DEBUG(NAME,STATE)\
fprintf(stderr,"%s (%s:%d): %s ",__func__,__FILE__,__LINE__,NAME);\
freesteam_fprint(stderr,S);
#else
# define FREESTEAM_DEBUG(NAME,STATE)
#endif
typedef double SteamPropertyFunction(SteamState S);
FREESTEAM_DLL double freesteam_p(SteamState S);
FREESTEAM_DLL double freesteam_T(SteamState S);
FREESTEAM_DLL double freesteam_rho(SteamState S);
FREESTEAM_DLL double freesteam_v(SteamState S);
FREESTEAM_DLL double freesteam_u(SteamState S);
FREESTEAM_DLL double freesteam_h(SteamState S);
FREESTEAM_DLL double freesteam_s(SteamState S);
FREESTEAM_DLL double freesteam_cp(SteamState S);
FREESTEAM_DLL double freesteam_cv(SteamState S);
FREESTEAM_DLL double freesteam_w(SteamState S);
FREESTEAM_DLL double freesteam_x(SteamState S);
FREESTEAM_DLL double freesteam_mu(SteamState S);
FREESTEAM_DLL double freesteam_k(SteamState S);
#endif

View file

@ -0,0 +1,102 @@
/*
freesteam - IAPWS-IF97 steam tables library
Copyright (C) 2004-2009 John Pye
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#define FREESTEAM_BUILDING_LIB
#include "steam_pT.h"
#include "region1.h"
#include "region4.h"
#include "region2.h"
#include "region3.h"
#include "zeroin.h"
#include "b23.h"
#include <stdlib.h>
#include <assert.h>
#include <math.h>
typedef struct{
double p, T;
} SteamPTData;
static double pT_region3_fn(double rho, void *user_data){
#define D ((SteamPTData *)user_data)
return D->p - freesteam_region3_p_rhoT(rho, D->T);
#undef D
}
/**
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;
}

View file

@ -0,0 +1,29 @@
/*
freesteam - IAPWS-IF97 steam tables library
Copyright (C) 2004-2009 John Pye
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef FREESTEAM_STEAMPT_H
#define FREESTEAM_STEAMPT_H
#include "common.h"
#include "steam.h"
FREESTEAM_DLL SteamState freesteam_set_pT(double p, double T);
#endif

View file

@ -0,0 +1,198 @@
/*
freesteam - IAPWS-IF97 steam tables library
Copyright (C) 2004-2009 John Pye
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#define FREESTEAM_BUILDING_LIB
#include "steam_ph.h"
#include "region1.h"
#include "region2.h"
#include "region3.h"
#include "region4.h"
#include "b23.h"
#include "backwards.h"
#include "solver2.h"
#include "zeroin.h"
#include "common.h"
#include <stdio.h>
#include <stdlib.h>
int freesteam_bounds_ph(double p, double h, int verbose){
#define BOUND_WARN(MSG) \
if(verbose){\
fprintf(stderr,"%s (%s:%d): WARNING " MSG " (p = %g MPa, h = %g kJ/kg)\n"\
,__func__,__FILE__,__LINE__,p/1e6,h/1e3);\
}
if(p <= 0){
BOUND_WARN("p <= 0");
return 1;
}
if(p > IAPWS97_PMAX){
BOUND_WARN("p > PMAX");
return 2;
}
double hmax = freesteam_region2_h_pT(p,REGION2_TMAX);
if(h>hmax){
BOUND_WARN("h > hmax");
return 3;
}
double hmin = freesteam_region1_h_pT(p,IAPWS97_TMIN);
if(h < hmin){
BOUND_WARN("h < hmin");
return 4;
}
return 0;
#undef BOUND_WARN
}
int freesteam_region_ph(double p, double h){
//fprintf(stderr,"freesteam_set_ph(p = %f, h = %f)\n",p,h);
double p13 = 0;
p13 = freesteam_region4_psat_T(REGION1_TMAX);
//fprintf(stderr,"p13 = %lf MPa\n",p13/1.e6);
//fprintf(stderr,"check: %f\n",freesteam_region4_psat_T(REGION1_TMAX));
if(p <= p13){
double Tsat = freesteam_region4_Tsat_p(p);
double hf = freesteam_region1_h_pT(p,Tsat);
if(h<hf){
return 1;
}
double hg = freesteam_region2_h_pT(p,Tsat);
if(h>hg){
return 2;
}
/* this is the low-pressure portion of region 4 */
return 4;
}
double h13 = freesteam_region1_h_pT(p,REGION1_TMAX);
if(h <= h13){
return 1;
}
double T23 = freesteam_b23_T_p(p);
//fprintf(stderr,"p = %f MPa --> T23(p) = %f K (%f °C)\n",p/1e6,T23,T23-273.15);
double h23 = freesteam_region2_h_pT(p,T23);
if(h >= h23){
return 2;
}
double psat = freesteam_region3_psat_h(h);
if(p > psat){
return 3;
}
/* high-pressure portion of region 4 */
return 4;
}
typedef struct SolvePHData_struct{
double p, h;
} SolvePHData;
#define D ((SolvePHData *)user_data)
static ZeroInSubjectFunction ph_region2_fn;
double ph_region2_fn(double T, void *user_data){
return D->h - freesteam_region2_h_pT(D->p, T);
}
#undef D
SteamState freesteam_set_ph(double p, double h){
SteamState S;
S.region = (char)freesteam_region_ph(p,h);
//int status;
switch(S.region){
case 1:
S.R1.p = p;
S.R1.T = freesteam_region1_T_ph(p, h);
#if 0
S = freesteam_solver2_region1('p','h', p, h, S, &status);
if(status){
fprintf(stderr,"%s: WARNING: Failed to converge in region 1\n",__func__);
}
#endif
return S;
case 2:
S.R2.p = p;
S.R2.T = freesteam_region2_T_ph(p, h);
{
double lb = S.R2.T * 0.999;
double ub = S.R2.T * 1.001;
double tol = 1e-9; /* ??? */
double sol, err;
SolvePHData D = {p, h};
zeroin_solve(&ph_region2_fn, &D, lb, ub, tol, &sol, &err);
S.R2.T = sol;
}
#if 0
/* solver2 is not working in this region, for some reason. */
S = freesteam_solver2_region2('p','h', p, h, S, &status);
if(status){
fprintf(stderr,"%s: WARNING: Failed to converge in region 2\n");
}
#endif
return S;
case 3:
S.R3.rho = 1./freesteam_region3_v_ph(p, h);
S.R3.T = freesteam_region3_T_ph(p, h);
#if 0
/* FIXME: this code doesn't work, see pTdiagram.h for example */
/* by not iterating here, the relative error is increased from
about 1e-12 to 1e-4 */
S = freesteam_solver2_region3('p','h', p, h, S, &status);
if(status){
fprintf(stderr,"%s: WARNING: Failed to converge in region 3\n",__func__);
}
#endif
return S;
case 4:
S.R4.T = freesteam_region4_Tsat_p(p);
//fprintf(stderr,"%s: region 4, Tsat = %g\n",__func__,S.R4.T);
double hf, hg;
if(S.R4.T <= REGION1_TMAX){
hf = freesteam_region1_h_pT(p,S.R4.T);
hg = freesteam_region2_h_pT(p,S.R4.T);
}else{
/* TODO iteratively improve estimate of T */
double rhof = freesteam_region4_rhof_T(S.R4.T);
double rhog = freesteam_region4_rhog_T(S.R4.T);
/* FIXME iteratively improve these estimates of rhof, rhog */
hf = freesteam_region3_h_rhoT(rhof,S.R4.T);
hg = freesteam_region3_h_rhoT(rhog,S.R4.T);
}
S.R4.x = (h - hf)/(hg - hf);
return S;
default:
fprintf(stderr,"%s: invalid region %d\n",__func__,S.region);
return S;
}
}

View file

@ -0,0 +1,32 @@
/*
freesteam - IAPWS-IF97 steam tables library
Copyright (C) 2004-2009 John Pye
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef FREESTEAM_STEAMPH_H
#define FREESTEAM_STEAMPH_H
#include "common.h"
#include "steam.h"
FREESTEAM_DLL int freesteam_bounds_ph(double p, double h, int verbose);
FREESTEAM_DLL int freesteam_region_ph(double p, double h);
FREESTEAM_DLL SteamState freesteam_set_ph(double p, double h);
#endif

View file

@ -0,0 +1,222 @@
/*
freesteam - IAPWS-IF97 steam tables library
Copyright (C) 2004-2009 John Pye
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#define FREESTEAM_BUILDING_LIB
#include "steam_pv.h"
#include "region1.h"
#include "region2.h"
#include "region3.h"
#include "region4.h"
#include "b23.h"
#include "backwards.h"
#include "solver2.h"
#include "zeroin.h"
#include "common.h"
#include <stdio.h>
#include <stdlib.h>
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
}
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;
}
}
typedef struct SolvePVData_struct{
double p, v;
} SolvePVData;
#define D ((SolvePVData *)user_data)
static ZeroInSubjectFunction pv_region1_fn;
double pv_region1_fn(double T, void *user_data){
return D->v - freesteam_region1_v_pT(D->p, T);
}
static ZeroInSubjectFunction pv_region2_fn;
double pv_region2_fn(double T, void *user_data){
return D->v - freesteam_region2_v_pT(D->p, T);
}
#undef D
typedef struct SolvePRhoData_struct{
double p, rho;
} SolvePRhoData;
#define D ((SolvePRhoData *)user_data)
static ZeroInSubjectFunction pv_region3_fn;
double pv_region3_fn(double T, void *user_data){
return D->p - freesteam_region3_p_rhoT(D->rho, T);
}
#undef D
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;
}

View file

@ -0,0 +1,32 @@
/*
freesteam - IAPWS-IF97 steam tables library
Copyright (C) 2004-2009 John Pye
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef FREESTEAM_STEAMPV_H
#define FREESTEAM_STEAMPV_H
#include "common.h"
#include "steam.h"
FREESTEAM_DLL int freesteam_bounds_pv(double p, double v, int verbose);
FREESTEAM_DLL int freesteam_region_pv(double p, double v);
FREESTEAM_DLL SteamState freesteam_set_pv(double p, double v);
#endif

View file

@ -0,0 +1,41 @@
/*
freesteam - IAPWS-IF97 steam tables library
Copyright (C) 2004-2009 John Pye
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#define FREESTEAM_BUILDING_LIB
#include "surftens.h"
#include <math.h>
/**
Calculate surface tension between water phase and vapour phase
@param T temperature (Kelvin)
@return surface tension (N/m)
The correlation is the IAPWS Release on Surface Tension of Ordinary Water
Substance, September 1994.
@since 0.7
*/
double freesteam_surftens_T(double T){
double tau = 1. - T / IAPWS97_TCRIT;
const double B = 235.8e-3; /* converted to N/m */
const double b = -0.625;
const double mu = 1.256;
return B * pow(tau,mu) * (1 + b * tau);
}

View file

@ -0,0 +1,31 @@
/*
freesteam - IAPWS-IF97 steam tables library
Copyright (C) 2004-2005 John Pye
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*//** @file
Function to calculate surface tension as a function of
temperature.
*/
#ifndef FREESTEAM_SURFTENS_H
#define FREESTEAM_SURFTENS_H
#include "common.h"
FREESTEAM_DLL double freesteam_surftens_T(double T);
#endif /* FREESTEAM_SURFTENS_H */

View file

@ -0,0 +1,102 @@
/*
freesteam - IAPWS-IF97 steam tables library
Copyright (C) 2004-2009 John Pye
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/* Appendix B: Recommended Interpolating equation for Industrial Use */
/* see http://www.iapws.org/relguide/thcond.pdf */
#define FREESTEAM_BUILDING_LIB
#include "thcond.h"
#include <math.h>
#define THCOND_TSTAR 647.26
#define THCOND_RHOSTAR 317.7
#define THCOND_KSTAR 1.0
#define THCOND_b0 -0.397070
#define THCOND_b1 0.400302
#define THCOND_b2 1.060000
#define THCOND_B1 -0.171587
#define THCOND_B2 2.392190
#define THCOND_C1 0.642857
#define THCOND_C2 -4.11717
#define THCOND_C3 -6.17937
#define THCOND_C4 0.00308976
#define THCOND_C5 0.0822994
#define THCOND_C6 10.0932
#define THCOND_d1 0.0701309
#define THCOND_d2 0.0118520
#define THCOND_d3 0.00169937
#define THCOND_d4 -1.0200
/* freesteam code */
double freesteam_k_rhoT(double rho, double T){
#define THCOND_a_COUNT 4
const double THCOND_a[THCOND_a_COUNT] = {
0.0102811
,0.0299621
,0.0156146
,-0.00422464
};
double Tbar = T / THCOND_TSTAR;
double rhobar = rho / THCOND_RHOSTAR;
/* fast implementation... minimised calls to 'pow' routine... */
double Troot = sqrt(Tbar);
double Tpow = Troot;
double lam = 0;
int k;
for(k = 0; k < THCOND_a_COUNT; ++k) {
lam += THCOND_a[k] * Tpow;
Tpow *= Tbar;
}
lam += THCOND_b0 + THCOND_b1 * rhobar + THCOND_b2 * exp(THCOND_B1 * SQ(rhobar + THCOND_B2));
double DTbar = fabs(Tbar - 1) + THCOND_C4;
double DTbarpow = pow(DTbar, 3./5);
double Q = 2. + THCOND_C5 / DTbarpow;
double S;
if(Tbar >= 1){
S = 1. / DTbar;
}else{
S = THCOND_C6 / DTbarpow;
}
double rhobar18 = pow(rhobar, 1.8);
double rhobarQ = pow(rhobar, Q);
lam +=
(THCOND_d1 / ipow(Tbar,10) + THCOND_d2) * rhobar18 *
exp(THCOND_C1 * (1 - rhobar * rhobar18))
+ THCOND_d3 * S * rhobarQ *
exp((Q/(1+Q))*(1 - rhobar*rhobarQ))
+ THCOND_d4 *
exp(THCOND_C2 * ipow(Troot,3) + THCOND_C3 / ipow(rhobar,5));
return THCOND_KSTAR * lam;
}

View file

@ -0,0 +1,38 @@
/*
freesteam - IAPWS-IF97 steam tables library
Copyright (C) 2004-2009 John Pye
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef FREESTEAM_THCOND_H
#define FREESTEAM_THCOND_H
#include "common.h"
/// Conductivity [W/m.K]
/**
Returns the thermal conductivity of water/steam.
@see http://www.iapws.org/relguide/thcond.pdf
Range of validity is entire regions 1,2,3. The correlation is not
really applicable in region 4, but will give 'sane' results there.
@return Thermal conductivity [W/m.K]
*/
FREESTEAM_DLL double freesteam_k_rhoT(double rho, double T);
#endif

View file

@ -0,0 +1,76 @@
# -*- coding: utf-8 -*-
# freesteam - IAPWS-IF97 steam tables library
# Copyright (C) 2004-2009 John Pye
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation; either version 2 of
# the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public
# License along with this program; if not, write to the Free
# Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
# Boston, MA 02110-1301, USA.
from math import exp
from freesteam import *
def tc_ptrho(p,T, rho):
"""
Revised release on the IAPS Formulation 1985 for the Thermal Conductivity of ordinary water
IAPWS September 1998
Page 8
Converted from Python from the XSteam OpenOffice version.
"""
print "rho = %f, T = %f" % (rho, T)
# ver2.6 Start corrected bug
if T < 273.15:
raise RuntimeWarning("T under range")
elif T < 500 + 273.15:
if p > 100:
raise RuntimeWarning("p over range for T<500°C")
elif T <= 650 + 273.15:
if p > 70:
raise RuntimeWarning("p over range for T<650°C")
elif T <= 800 + 273.15:
if p > 40:
raise RuntimeWarning("p over range for T<800°C")
# ver2.6 End corrected bug
T = T / 647.26
rho = rho / 317.7
lam0 = T ** 0.5 * (0.0102811 + 0.0299621 * T + 0.0156146 * T ** 2 - 0.00422464 * T ** 3)
lam1 = -0.39707 + 0.400302 * rho + 1.06 * exp(-0.171587 * (rho + 2.39219) ** 2)
dT = abs(T - 1) + 0.00308976
Q = 2 + 0.0822994 / dT ** (3. / 5)
if T >= 1:
s = 1. / dT
else:
s = 10.0932 / dT ** (3. / 5)
lam2 = (0.0701309 / T ** 10 + 0.011852) * rho ** (9. / 5) * exp(0.642857 * (1 - rho ** (14. / 5))) + 0.00169937 * s * rho ** Q * exp((Q / (1. + Q)) * (1. - rho ** (1. + Q))) - 1.02 * exp(-4.11717 * T ** (3. / 2) - 6.17937 / rho ** 5)
print "lam0 = %f, lam1 = %f, lam2 = %f" % (lam0, lam1, lam2)
return lam0 + lam1 + lam2
if __name__=='__main__':
p = 5
T = 300
rho = steam_pT(p * 1e6,T + 273.15).rho
print "p = %f MPa" % p
print "T = %f °C" % T
print "rho = %f kg/m³" % rho
k = tc_ptrho(p, T + 273.15, rho)
print "k =",k

View file

@ -0,0 +1,78 @@
/*
freesteam - IAPWS-IF97 steam tables library
Copyright (C) 2004-2009 John Pye
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/*
Based on IAPWS Formulation 2008 for the Viscosity of Ordinary Water Substance
*/
#define FREESTEAM_BUILDING_LIB
#include "viscosity.h"
static double mu0(double tau);
static double mu1(double del, double tau);
#define VISCOSITY_MUSTAR 1.0e-6 /* Pa-s */
#include <math.h>
static double mu0(double tau){
// viscosity in the dilute-gas limit
const double H[4] = {1.67752, 2.20462, 0.6366564, -0.241605};
int i;
double sum = 0;
for (i = 0; i < 4; i++){
sum += H[i] * ipow(tau, i) ;
}
return 100.0 / (sqrt(tau) * sum);
}
static double mu1(double del, double tau){
// contribution to viscosity due to finite density
const double H[6][7] = {
{ 5.20094E-1, 2.22531E-1, -2.81378E-1, 1.61913E-1, -3.25372E-2, 0.0, 0.0},
{ 8.50895E-2, 9.99115E-1, -9.06851E-1, 2.57399E-1, 0.0, 0.0, 0.0},
{-1.08374, 1.88797, -7.72479E-1, 0.0, 0.0, 0.0, 0.0},
{-2.89555E-1, 1.26613, -4.89837E-1, 0.0, 6.98452E-2, 0.0, -4.35673E-3},
{ 0.0, 0.0, -2.57040E-1, 0.0, 0.0, 8.72102E-3, 0.0},
{ 0.0, 1.20573E-1, 0.0, 0.0, 0.0, 0.0, -5.93264E-4}
};
int i, j;
double sum = 0;
double tau1 = 0;
for (i = 0; i < 6; i++){
tau1 = ipow(tau - 1, i);
for (j = 0; j < 7; j++){
if(0==H[i][j])continue;
sum += H[i][j] * tau1 * ipow(del - 1, j);
}
}
return exp(del * sum);
}
double freesteam_mu_rhoT(double rho, double T){
double del = rho / IAPWS97_RHOCRIT;
double tau = IAPWS97_TCRIT / T;
const int mu2 = 1; // critical enhancement to viscosity not implemented for IF-97, set to 1
return VISCOSITY_MUSTAR * mu0(tau) * mu1(del,tau) * mu2;
}

View file

@ -0,0 +1,31 @@
/*
freesteam - IAPWS-IF97 steam tables library
Copyright (C) 2004-2009 John Pye
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/*
Based on IAPWS Formulation 2008 for the Viscosity of Ordinary Water Substance
*/
#ifndef FREESTEAM_VISCOSITY_H
#define FREESTEAM_VISCOSITY_H
#include "common.h"
FREESTEAM_DLL double freesteam_mu_rhoT(double rho, double T);
#endif

View file

@ -0,0 +1,142 @@
/*
freesteam - IAPWS-IF97 steam tables library
Copyright (C) 2004-2009 John Pye
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#define FREESTEAM_BUILDING_LIB
#include "zeroin.h"
#include <math.h>
#include <stdio.h>
#ifndef DBL_EPSILON
#define DBL_EPSILON 2e-16
#endif
char zeroin_solve(ZeroInSubjectFunction *func, void *user_data, double lowerbound, double upperbound, double tol, double *solution, double *error){
double a, b, c; ///< Abscissae, descr. see above.
double fa; ///< f(a)
double fb; ///< f(b)
double fc; ///< f(c)
a = lowerbound;
b = upperbound;
fa = (*func)(a,user_data);
fb = (*func)(b,user_data);
c = a;
fc = fa;
if(fa == 0.){
*error = 0.; // used by getError
*solution = a;
//fprintf(stderr,"perfect solution\n");
return 0;
}
// Main iteration loop
for (;;) {
double prev_step = b - a; ///< Distance from the last but one to the last approximation
double tol_act; ///< Actual tolerance
double p; ///< Interpolation step is calculated in the form p/q; division
double q; ///< operations is delayed until the last moment
double new_step; ///< Step at this iteration
if (fabs(fc) < fabs(fb)) {
a = b;
b = c;
c = a; // Swap data for b to be the best approximation
fa = fb;
fb = fc;
fc = fa;
}
// DBL_EPSILON is defined in math.h
tol_act = 2.0* DBL_EPSILON * fabs(b) + tol / 2.0;
new_step = (c - b) / 2.0;
//fprintf(stderr,"step = %g\n",new_step);
if (fabs(new_step) <= tol_act || fb == 0.) {
*error = fb;
*solution = b;
//fprintf(stderr,"best solution is b: f(b=%g) = %g, f(a=%g) = %g\n",b,fb,a,fb);
return 0;
}
// Decide if the interpolation can be tried
if (fabs(prev_step) >= tol_act // If prev_step was large enough and was in true direction,
&& fabs(fa) > fabs(fb)) // Interpolatiom may be tried
{
register double t1, t2;
double cb;
cb = c - b;
if (a == c) {
// If we have only two distinct points
// then only linear interpolation can be applied
t1 = fb / fa;
p = cb * t1;
q = 1.0 - t1;
} else {
// Quadric inverse interpolation
q = fa / fc;
t1 = fb / fc;
t2 = fb / fa;
p = t2 * (cb * q * (q - t1) - (b - a) * (t1 - 1.0));
q = (q - 1.0) * (t1 - 1.0) * (t2 - 1.0);
}
if (p > 0.) {
// p was calculated with the opposite sign; make p positive-
q = -q; // and assign possible minus to q
} else {
p = -p;
}
if (p < (0.75 * cb * q - fabs(tol_act * q) / 2.0)
&& p < fabs(prev_step * q / 2.0)
) {
// If b+p/q falls in [b,c] and
// isn't too large it is accepted
new_step = p / q;
}
// If p/q is too large then the bissection procedure can
// reduce [b,c] range to more extent
}
if (fabs(new_step) < tol_act) { // Adjust the step to be not less
if (new_step > 0.) // than tolerance
new_step = tol_act;
else
new_step = -tol_act;
}
a = b;
fa = fb; // Save the previous approx.
b += new_step;
fb = (*func)(b,user_data); // Do step to a new approxim.
if ((fb > 0. && fc > 0.)
|| (fb < 0. && fc < 0.)) {
c = a;
fc = fa; // Adjust c for it to have a sign opposite to that of b
}
}
// (((we never arrive here)))
}

View file

@ -0,0 +1,65 @@
/*
freesteam - IAPWS-IF97 steam tables library
Copyright (C) 2004-2009 John Pye
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef FREESTEAM_ZEROIN_H
#define FREESTEAM_ZEROIN_H
#include "common.h"
/**
Any function that you want to solve using the 'zeroin_solve' function
needs to conform to this function prototype. Any parameters required
internally by the function can be passed in to the function as a pointer
to a struct, array, etc, via the void 'user_data' pointer. Your subject
function can then cast the pointer to its correct type, and access the
necesssary parameter data, for example:
-- in your main code
typedef struct{double param1, param2} MyData;
MyData D = {100., 3.141};
double myfunc(double x, void *user_data){
MyData *D1 = (MyData *)user_data;
return x * D1->param1 + D1->param2;
}
zeroin_solve(&myfunc, &D, ...);
*/
typedef double ZeroInSubjectFunction(double, void *user_data);
/**
Attempt to solve the function y = f(x) = 0 by varying x between
a lower and upper bound, using the Brent algorithm.
Originally based on brent solver from netlib, then converted to C++ for
used in earlier freesteam versions, and now converted back to pure C again.
@see brent.shar at http://www.netlib.org/c/
@param func the function being solved, must be a ZeroInSubjectFunction.
@param lowerbound the lower bound of the range in which a root is sought
@param upperbound the upper bound of the range in which a root is sought
@param tol maximum permissible magnitude of the function at the solved root location
@param user_data additional data that will be passed to the subject function func.
@param solution (returned) the value of 'x' at the solution
@param error (returned) the value of 'y' at the solution.
@return 0 on success
*/
FREESTEAM_DLL char zeroin_solve(ZeroInSubjectFunction *func, void *user_data, double lowerbound, double upperbound, double tol, double *solution, double *error);
#endif

View file

@ -0,0 +1,49 @@
/*--------------------------------*- C++ -*----------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: 1.7.1 |
| \\ / A nd | Web: www.OpenFOAM.com |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
FoamFile
{
version 2.0;
format ascii;
class volScalarField;
location "0";
object T;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
dimensions [0 0 0 1 0 0 0];
internalField uniform 333.15;
boundaryField
{
inlet
{
type fixedValue;
value uniform 333.15;
}
outlet
{
type zeroGradient;
}
upperWall
{
type zeroGradient;
}
lowerWall
{
type zeroGradient;
}
frontAndBack
{
type empty;
}
}
// ************************************************************************* //

View file

@ -0,0 +1,51 @@
/*--------------------------------*- C++ -*----------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: 1.7.1 |
| \\ / A nd | Web: www.OpenFOAM.com |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
FoamFile
{
version 2.0;
format ascii;
class volVectorField;
location "0";
object U;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
dimensions [0 1 -1 0 0 0 0];
internalField uniform (0 0 0);
boundaryField
{
inlet
{
type pressureInletVelocity;
value uniform (3.5 0 0);
}
outlet
{
type zeroGradient;
}
upperWall
{
type fixedValue;
value uniform (0 0 0);
}
lowerWall
{
type fixedValue;
value uniform (0 0 0);
}
frontAndBack
{
type empty;
}
}
// ************************************************************************* //

Some files were not shown because too many files have changed in this diff Show more