This commit is contained in:
TJP-Karpowski 2025-02-14 13:30:42 +00:00 committed by GitHub
commit 2c5f9bd808
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 133 additions and 5 deletions

View File

@ -366,7 +366,7 @@ public:
* @param p Pressure (Pa)
* @since New in %Cantera 3.0.
*/
void setState_DP(double rho, double p) override {
void setState_DP(double rho, double p, double Tguess=300) override {
if (p <= 0) {
throw CanteraError("IdealGasPhase::setState_DP",
"pressure must be positive");

View File

@ -88,7 +88,7 @@ public:
* -1 means gas. The value -2 means unrestricted. Values of zero or
* greater refer to species dominated condensed phases.
*/
void setForcedSolutionBranch(int solnBranch);
void setForcedSolutionBranch(int solnBranch) override;
//! Report the solution branch which the solution is restricted to
/*!

View File

@ -203,6 +203,7 @@ protected:
* These are stored internally.
*/
double daAlpha_dT() const;
double daAlpha_dT(double& temp) const;
//! Calculate second derivative @f$ d^2(a \alpha)/dT^2 @f$
/*!
@ -211,6 +212,7 @@ protected:
double d2aAlpha_dT2() const;
public:
void setState_DP(double rho, double p, double Tguess=300) override;
double isothermalCompressibility() const override;
double thermalExpansionCoeff() const override;
@ -229,7 +231,7 @@ public:
* the internal numbers based on the state of the object.
*/
void updateMixingExpressions() override;
void updateMixingExpressions(double& temp,double& aCalc, double& bCalc, double& aAlphaCalc);
//! Calculate the @f$ a @f$, @f$ b @f$, and @f$ \alpha @f$ parameters given the temperature
/*!
* This function doesn't change the internal state of the object, so it is a

View File

@ -1401,10 +1401,18 @@ public:
* @param p Pressure (Pa)
* @since New in %Cantera 3.0.
*/
virtual void setState_DP(double rho, double p) {
virtual void setState_DP(double rho, double p, double Tguess=300) {
throw NotImplementedError("ThermoPhase::setState_DP",
"Not implemented for phase type '{}'", type());
}
//! Set the solution branch to force the ThermoPhase to exist on one branch
//! or another
/*!
* @param solnBranch Branch that the solution is restricted to. the value
* -1 means gas. The value -2 means unrestricted. Values of zero or
* greater refer to species dominated condensed phases.
*/
virtual void setForcedSolutionBranch(int solnBranch){};
//! Set the state using an AnyMap containing any combination of properties
//! supported by the thermodynamic model

View File

@ -835,7 +835,8 @@ int MixtureFugacityTP::solveCubic(double T, double pres, double a, double b,
if (fabs(fabs(h) - fabs(yN)) < 1.0E-10) {
if (disc > 1e-10) {
throw CanteraError("MixtureFugacityTP::solveCubic",
"value of yN and h are too high, unrealistic roots may be obtained");
"value of yN and h are too high, unrealistic roots may be obtained"
);
}
disc = 0.0;
}

View File

@ -673,6 +673,28 @@ void PengRobinson::updateMixingExpressions()
calculateAB(m_a,m_b,m_aAlpha_mix);
}
void PengRobinson::updateMixingExpressions(double& temp,double& aCalc, double& bCalc, double& aAlphaCalc)
{
//double temp = temperature();
// Update individual alpha
for (size_t j = 0; j < m_kk; j++) {
double critTemp_j = speciesCritTemperature(m_a_coeffs(j,j), m_b_coeffs[j]);
double sqt_alpha = 1 + m_kappa[j] * (1 - sqrt(temp / critTemp_j));
m_alpha[j] = sqt_alpha*sqt_alpha;
}
// Update aAlpha_i, j
for (size_t i = 0; i < m_kk; i++) {
for (size_t j = 0; j < m_kk; j++) {
m_aAlpha_binary(i, j) = sqrt(m_alpha[i] * m_alpha[j]) * m_a_coeffs(i,j);
}
}
calculateAB(aCalc,bCalc,aAlphaCalc);
}
void PengRobinson::calculateAB(double& aCalc, double& bCalc, double& aAlphaCalc) const
{
bCalc = 0.0;
@ -710,6 +732,30 @@ double PengRobinson::daAlpha_dT() const
return daAlphadT;
}
double PengRobinson::daAlpha_dT(double& temp) const
{
double daAlphadT = 0.0, k, Tc, sqtTr, coeff1, coeff2;
for (size_t i = 0; i < m_kk; i++) {
// Calculate first derivative of alpha for individual species
Tc = speciesCritTemperature(m_a_coeffs(i,i), m_b_coeffs[i]);
sqtTr = sqrt(temp / Tc);
coeff1 = 1 / (Tc*sqtTr);
coeff2 = sqtTr - 1;
k = m_kappa[i];
m_dalphadT[i] = coeff1 * (k*k*coeff2 - k);
}
// Calculate mixture derivative
for (size_t i = 0; i < m_kk; i++) {
for (size_t j = 0; j < m_kk; j++) {
daAlphadT += moleFractions_[i] * moleFractions_[j] * 0.5
* m_aAlpha_binary(i, j)
* (m_dalphadT[i] / m_alpha[i] + m_dalphadT[j] / m_alpha[j]);
}
}
return daAlphadT;
}
double PengRobinson::d2aAlpha_dT2() const
{
for (size_t i = 0; i < m_kk; i++) {
@ -792,4 +838,45 @@ AnyMap PengRobinson::getAuxiliaryData()
return parameters;
}
void PengRobinson::setState_DP(double rho, double p, double Tguess)
{
if (p <= 0 || rho<=0 ) {
throw CanteraError("PengRobinson::setState_DP",
"pressure and density must be positive");
}
setDensity(rho);
double mV = meanMolecularWeight() / rho;
// Update individual alpha
double aCalc, bCalc, aAlpha;
int iteration = 0;
double T_new = Tguess; //(p + term2) * denum / GasConstant;
double p_iter=p;
while (iteration < 300) {
// Update a, b, and alpha based on the current guess for T
updateMixingExpressions(T_new, aCalc, bCalc, aAlpha);
// Calculate p using PR EoS
double denom = mV * mV + 2 * mV * bCalc - bCalc * bCalc;
double mV_b = mV - bCalc;
double term2 = (aAlpha) / denom;
p_iter = (GasConstant*T_new)/mV_b - term2;
// Check if the result is within the specified tolerance
double error =(p_iter-p)/p;
if (fabs(error)<1e-10) {
break;
}
m_dpdT = (GasConstant / mV_b - daAlpha_dT(T_new) / denom);
T_new = T_new - (error/(m_dpdT/p));
iteration++;
}
if (iteration==300)
{
throw CanteraError("PengRobinson::DP did not converge at",
"negative temperature T = {} p= {} rho={} X1={} X2={}", T_new, p, rho,moleFractions_[0],moleFractions_[1]);
}
setDensity(rho);
setTemperature(T_new);
setState_TP(T_new,p);
updateMixingExpressions();
}
}

View File

@ -179,6 +179,36 @@ TEST_F(PengRobinson_Test, CoolPropValidate)
}
}
TEST_F(PengRobinson_Test, CoolPropValidateDP)
{
// Validate the P-R EoS in Cantera with P-R EoS from CoolProp
const double rhoCoolProp[10] = {
9.067928191884574,
8.318322900591179,
7.6883521740498155,
7.150504298001246,
6.685330199667018,
6.278630757480957,
5.919763108091383,
5.600572727499541,
5.314694056926007,
5.057077678380463
};
double p = 5e5;
// Calculate Temperature using Peng-Robinson EoS from Cantera
for(int i=0; i<10; i++)
{
const double tempReference = 300 + i*25;
set_r(1.0);
test_phase->setState_DP(rhoCoolProp[i], p,300);
EXPECT_NEAR(test_phase->temperature(),tempReference,1.e-3);
}
}
TEST(PengRobinson, lookupSpeciesProperties)
{
AnyMap phase_def = AnyMap::fromYamlString(