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:
parent
27d9b6413a
commit
68a89d0322
3 changed files with 6432 additions and 8 deletions
6276
data/inputs/critProperties.xml
Normal file
6276
data/inputs/critProperties.xml
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue