Adding critProperties database for RedlichKwongMFTP

Adds capability for RedlichKwongMFTP to read a database of critical properties
for Tc and Pc of common species, so that users do not need to input pureFluidParameters
for every single species, thereby reducing burden during creation of new cti files.

For any species where pureFluidParameters are not provided by the user, function
getCoeffs scans the database looking for matches.  Any unmatched species will throw
an error.  Currently only scans by species name string, and is only intended for
common species with well-known critical properties.

Current operation is quite slow if the table is consulted for a large number of
species.  In the future, should also implement the capability to write the updated
pureFluidParameters back into the xml file, so the user only has to perform the lookup
once.
This commit is contained in:
Steven DeCaluwe 2017-06-27 08:16:40 -06:00 committed by Ray Speth
parent 27d9b6413a
commit 68a89d0322
3 changed files with 6432 additions and 8 deletions

File diff suppressed because it is too large Load diff

View file

@ -178,6 +178,20 @@ public:
virtual void setToEquilState(const doublereal* lambda_RT);
virtual void initThermoXML(XML_Node& phaseNode, const std::string& id);
//! Retrieve a and b coefficients by looking up tabulated critical parameters
/*!
* If pureFluidParameters are not provided for any species in the phase,
* consult the critical properties tabulated in /thermo/critProperties.xml.
* If the species is found there, calculate pure fluid parameters a_k and b_k as:
* \f[ a_k = 0.4278*R**2*T_c^2.5/P_c \f]
*
* and:
* \f[ b_k = 0.08664*R*T_c/P_c \f]
*
* @param iName Name of the species
*/
virtual std::vector<double> getCoeff(const std::string& iName);
//! Set the pure fluid interaction parameters for a species
/*!
* The "a" parameter for species *i* in the Redlich-Kwong model is assumed

View file

@ -79,9 +79,17 @@ void RedlichKwongMFTP::setSpeciesCoeffs(const std::string& species,
if (k == j) {
continue;
}
double a0kj = sqrt(a_coeff_vec(0, j + m_kk * j) * a0);
double a1kj = sqrt(a_coeff_vec(1, j + m_kk * j) * a1);
if (a_coeff_vec(0, j + m_kk * k) == 0) {
// a_coeff_vec is initialized to -1, so screen for unidentified species to prevent
// imaginary numbers on the off-diagonals:
if (a_coeff_vec(0, j + m_kk * j) < 0 || a_coeff_vec(1, j + m_kk * j) < 0){
// The diagonal element of the jth species has not yet been defined.
continue;
} else if (a_coeff_vec(0, j + m_kk * k) == -1) {
// Only use the mixing rules if the off-diagonal element has not already been defined by a
// user-specified crossFluidParameters entry:
double a0kj = sqrt(a_coeff_vec(0, j + m_kk * j) * a0);
double a1kj = sqrt(a_coeff_vec(1, j + m_kk * j) * a1);
a_coeff_vec(0, j + m_kk * k) = a0kj;
a_coeff_vec(1, j + m_kk * k) = a1kj;
a_coeff_vec(0, k + m_kk * j) = a0kj;
@ -546,9 +554,11 @@ bool RedlichKwongMFTP::addSpecies(shared_ptr<Species> spec)
bool added = MixtureFugacityTP::addSpecies(spec);
if (added) {
a_vec_Curr_.resize(m_kk * m_kk, 0.0);
b_vec_Curr_.push_back(0.0);
a_coeff_vec.resize(2, m_kk * m_kk, 0.0);
// Initialize a_vec and b_vec to -1, to screen for species with
// pureFluidParameters which are undefined in the input file:
b_vec_Curr_.push_back(-1);
a_coeff_vec.resize(2, m_kk * m_kk, -1);
m_pp.push_back(0.0);
m_tmpV.push_back(0.0);
@ -573,13 +583,61 @@ void RedlichKwongMFTP::initThermoXML(XML_Node& phaseNode, const std::string& id)
if (thermoNode.hasChild("activityCoefficients")) {
XML_Node& acNode = thermoNode.child("activityCoefficients");
// Loop through the children getting multiple instances of
// parameters
// Count the number of species with parameters provided in the
// input file:
size_t nParams = 0;
// Loop through the children and read out fluid parameters. Process
// all the pureFluidParameters, first:
for (size_t i = 0; i < acNode.nChildren(); i++) {
XML_Node& xmlACChild = acNode.child(i);
if (caseInsensitiveEquals(xmlACChild.name(), "purefluidparameters")) {
readXMLPureFluid(xmlACChild);
} else if (caseInsensitiveEquals(xmlACChild.name(), "crossfluidparameters")) {
nParams += 1;
}
}
// If any species exist which have undefined pureFluidParameters,
// search the database in 'critProperties.xml' to find critical
// temperature and pressure to calculate a and b.
// Loop through all species in the CTI file
size_t iSpecies = 0;
for (size_t i = 0; i < m_kk; i++) {
string iName = speciesName(i);
// Get the index of the species
iSpecies = speciesIndex(iName);
// Check if a and b are already populated (only the diagonal elements of a).
size_t counter = iSpecies + m_kk * iSpecies;
// If not, then search the database:
if (a_coeff_vec(0, counter) == -1 ||
b_vec_Curr_[iSpecies] == -1) {
vector<double> coeffArray;
// Search the database for the species name and calculate
// coefficients a and b, from critical properties:
// coeffArray[0] = a0, coeffArray[1] = b;
coeffArray = getCoeff(iName);
// Check if species was found in the database of critical properties,
// and assign the results
if (coeffArray[0] != -1 || coeffArray[1] != -1) {
//Assuming no temperature dependence (i,e a1 = 0)
setSpeciesCoeffs(iName, coeffArray[0], 0.0, coeffArray[1]);
}
}
}
// Loop back through the "activityCoefficients" children and process the
// crossFluidParameters in the XML tree:
for (size_t i = 0; i < acNode.nChildren(); i++) {
XML_Node& xmlACChild = acNode.child(i);
if (caseInsensitiveEquals(xmlACChild.name(), "crossfluidparameters")) {
readXMLCrossFluid(xmlACChild);
}
}
@ -589,6 +647,82 @@ void RedlichKwongMFTP::initThermoXML(XML_Node& phaseNode, const std::string& id)
MixtureFugacityTP::initThermoXML(phaseNode, id);
}
vector<double> RedlichKwongMFTP::getCoeff(const std::string& iName)
{
vector_fp vParams;
bool found = false;
vector<double> spCoeff(2);
spCoeff[0] = -1;
spCoeff[1] = -1;
// Get number of species in the database
// open xml file critProperties.xml
XML_Node* doc = get_XML_File("critProperties.xml");
size_t nDatabase = doc->nChildren();
// Loop through all species in the database and attempt to match supplied
// species to each. If present, calculate pureFluidParameters a_k and b_k
// based on crit properties T_c and P_c:
for (size_t isp = 0; isp < nDatabase; isp++) {
XML_Node& acNodeDoc = doc->child(isp);
std::string iNameLower = toLowerCopy(iName);
std::string dbName = toLowerCopy(acNodeDoc.attrib("name"));
// Attempt to match provided specie iName to current database species
// dbName:
if (iNameLower == dbName) {
// Read from database and calculate a and b coefficients
double vParams;
double T_crit, P_crit;
if (acNodeDoc.hasChild("Tc")) {
vParams = 0.0;
XML_Node& xmlChildCoeff = acNodeDoc.child("Tc");
if (xmlChildCoeff.hasAttrib("value"))
{
std::string critTemp = xmlChildCoeff.attrib("value");
vParams = strSItoDbl(critTemp);
}
if (vParams <= 0.0) //Assuming that Pc and Tc are non zero.
{
throw CanteraError("RedlichKwongMFTP::GetCoeff",
"Critical Temperature must be positive ");
}
T_crit = vParams;
}
if (acNodeDoc.hasChild("Pc")) {
vParams = 0.0;
XML_Node& xmlChildCoeff = acNodeDoc.child("Pc");
if (xmlChildCoeff.hasAttrib("value"))
{
std::string critPressure = xmlChildCoeff.attrib("value");
vParams = strSItoDbl(critPressure);
}
if (vParams <= 0.0) //Assuming that Pc and Tc are non zero.
{
throw CanteraError("RedlichKwongMFTP::GetCoeff",
"Critical Pressure must be positive ");
}
P_crit = vParams;
}
//Assuming no temperature dependence
spCoeff[0] = omega_a * pow(GasConstant, 2) * pow(T_crit, 2.5) / P_crit; //coeff a
spCoeff[1] = omega_b * GasConstant * T_crit / P_crit; // coeff b
found = true;
break;
}
}
if (!found) {
// Species is present in neither CTI/xml nor database: throw error
throw CanteraError("RedlichKwongMFTP::getCoeff",
"pureFluidParameters for species " +
iName + " are undefined");
}
return spCoeff;
}
void RedlichKwongMFTP::readXMLPureFluid(XML_Node& pureFluidParam)
{
string xname = pureFluidParam.name();