329 lines
11 KiB
C++
329 lines
11 KiB
C++
/**
|
|
* @file vcs_prep.cpp
|
|
* This file contains some prepatory functions.
|
|
*/
|
|
|
|
/*
|
|
* Copyright (2005) Sandia Corporation. Under the terms of
|
|
* Contract DE-AC04-94AL85000 with Sandia Corporation, the
|
|
* U.S. Government retains certain rights in this software.
|
|
*/
|
|
|
|
#include "cantera/equil/vcs_solve.h"
|
|
#include "cantera/equil/vcs_internal.h"
|
|
#include "cantera/equil/vcs_prob.h"
|
|
#include "cantera/equil/vcs_VolPhase.h"
|
|
#include "cantera/equil/vcs_SpeciesProperties.h"
|
|
|
|
#include <cstdio>
|
|
#include <cstdlib>
|
|
#include <cmath>
|
|
|
|
namespace VCSnonideal
|
|
{
|
|
|
|
|
|
// Calculate the status of single species phases.
|
|
void VCS_SOLVE::vcs_SSPhase()
|
|
{
|
|
size_t iph;
|
|
vcs_VolPhase* Vphase;
|
|
|
|
std::vector<int> numPhSpecies(m_numPhases, 0);
|
|
|
|
for (size_t kspec = 0; kspec < m_numSpeciesTot; ++kspec) {
|
|
numPhSpecies[m_phaseID[kspec]]++;
|
|
}
|
|
/*
|
|
* Handle the special case of a single species in a phase that
|
|
* has been earmarked as a multispecies phase.
|
|
* Treat that species as a single-species phase
|
|
*/
|
|
for (iph = 0; iph < m_numPhases; iph++) {
|
|
Vphase = m_VolPhaseList[iph];
|
|
Vphase->m_singleSpecies = false;
|
|
if (TPhInertMoles[iph] > 0.0) {
|
|
Vphase->setExistence(2);
|
|
}
|
|
if (numPhSpecies[iph] <= 1) {
|
|
if (TPhInertMoles[iph] == 0.0) {
|
|
Vphase->m_singleSpecies = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Fill in some useful arrays here that have to do with the
|
|
* static information concerning the phase ID of species.
|
|
* SSPhase = Boolean indicating whether a species is in a
|
|
* single species phase or not.
|
|
*/
|
|
for (size_t kspec = 0; kspec < m_numSpeciesTot; kspec++) {
|
|
iph = m_phaseID[kspec];
|
|
Vphase = m_VolPhaseList[iph];
|
|
if (Vphase->m_singleSpecies) {
|
|
m_SSPhase[kspec] = true;
|
|
} else {
|
|
m_SSPhase[kspec] = false;
|
|
}
|
|
}
|
|
}
|
|
/*****************************************************************************/
|
|
|
|
// This routine is mostly concerned with changing the private data
|
|
// to be consistent with what's needed for solution. It is called one
|
|
// time for each new problem structure definition.
|
|
/*
|
|
* This routine is always followed by vcs_prep(). Therefore, tasks
|
|
* that need to be done for every call to vcsc() should be placed in
|
|
* vcs_prep() and not in this routine.
|
|
*
|
|
* The problem structure refers to:
|
|
*
|
|
* the number and identity of the species.
|
|
* the formula matrix and thus the number of components.
|
|
* the number and identity of the phases.
|
|
* the equation of state
|
|
* the method and parameters for determining the standard state
|
|
* The method and parameters for determining the activity coefficients.
|
|
*
|
|
* Tasks:
|
|
* 0) Fill in the SSPhase[] array.
|
|
* 1) Check to see if any multispecies phases actually have only one
|
|
* species in that phase. If true, reassign that phase and species
|
|
* to be a single-species phase.
|
|
* 2) Determine the number of components in the problem if not already
|
|
* done so. During this process the order of the species is changed
|
|
* in the private data structure. All references to the species
|
|
* properties must employ the ind[] index vector.
|
|
*
|
|
* @param printLvl Print level of the routine
|
|
*
|
|
* @return the return code
|
|
* VCS_SUCCESS = everything went OK
|
|
*
|
|
*/
|
|
int VCS_SOLVE::vcs_prep_oneTime(int printLvl)
|
|
{
|
|
size_t kspec, i;
|
|
int retn = VCS_SUCCESS;
|
|
double pres, test;
|
|
double* aw, *sa, *sm, *ss;
|
|
bool modifiedSoln = false;
|
|
bool conv;
|
|
|
|
m_debug_print_lvl = printLvl;
|
|
|
|
|
|
/*
|
|
* Calculate the Single Species status of phases
|
|
* Also calculate the number of species per phase
|
|
*/
|
|
vcs_SSPhase();
|
|
|
|
/*
|
|
* Set an initial estimate for the number of noncomponent species
|
|
* equal to nspecies - nelements. This may be changed below
|
|
*/
|
|
if (m_numElemConstraints > m_numSpeciesTot) {
|
|
m_numRxnTot = 0;
|
|
} else {
|
|
m_numRxnTot = m_numSpeciesTot - m_numElemConstraints;
|
|
}
|
|
m_numRxnRdc = m_numRxnTot;
|
|
m_numSpeciesRdc = m_numSpeciesTot;
|
|
for (i = 0; i < m_numRxnRdc; ++i) {
|
|
m_indexRxnToSpecies[i] = m_numElemConstraints + i;
|
|
}
|
|
|
|
for (kspec = 0; kspec < m_numSpeciesTot; ++kspec) {
|
|
size_t pID = m_phaseID[kspec];
|
|
size_t spPhIndex = m_speciesLocalPhaseIndex[kspec];
|
|
vcs_VolPhase* vPhase = m_VolPhaseList[pID];
|
|
vcs_SpeciesProperties* spProp = vPhase->speciesProperty(spPhIndex);
|
|
double sz = 0.0;
|
|
size_t eSize = spProp->FormulaMatrixCol.size();
|
|
for (size_t e = 0; e < eSize; e++) {
|
|
sz += fabs(spProp->FormulaMatrixCol[e]);
|
|
}
|
|
if (sz > 0.0) {
|
|
m_spSize[kspec] = sz;
|
|
} else {
|
|
m_spSize[kspec] = 1.0;
|
|
}
|
|
}
|
|
|
|
/* ***************************************************** */
|
|
/* **** DETERMINE THE NUMBER OF COMPONENTS ************* */
|
|
/* ***************************************************** */
|
|
|
|
/*
|
|
* Obtain a valid estimate of the mole fraction. This will
|
|
* be used as an initial ordering vector for prioritizing
|
|
* which species are defined as components.
|
|
*
|
|
* If a mole number estimate was supplied from the
|
|
* input file, use that mole number estimate.
|
|
*
|
|
* If a solution estimate wasn't supplied from the input file,
|
|
* supply an initial estimate for the mole fractions
|
|
* based on the relative reverse ordering of the
|
|
* chemical potentials.
|
|
*
|
|
* For voltage unknowns, set these to zero for the moment.
|
|
*/
|
|
test = -1.0e-10;
|
|
if (m_doEstimateEquil < 0) {
|
|
double sum = 0.0;
|
|
for (kspec = 0; kspec < m_numSpeciesTot; ++kspec) {
|
|
if (m_speciesUnknownType[kspec] == VCS_SPECIES_TYPE_MOLNUM) {
|
|
sum += fabs(m_molNumSpecies_old[kspec]);
|
|
}
|
|
}
|
|
if (fabs(sum) < 1.0E-6) {
|
|
modifiedSoln = true;
|
|
if (m_pressurePA <= 0.0) {
|
|
pres = 1.01325E5;
|
|
} else {
|
|
pres = m_pressurePA;
|
|
}
|
|
retn = vcs_evalSS_TP(0, 0, m_temperature, pres);
|
|
for (kspec = 0; kspec < m_numSpeciesTot; ++kspec) {
|
|
if (m_speciesUnknownType[kspec] == VCS_SPECIES_TYPE_MOLNUM) {
|
|
m_molNumSpecies_old[kspec] = - m_SSfeSpecies[kspec];
|
|
} else {
|
|
m_molNumSpecies_old[kspec] = 0.0;
|
|
}
|
|
}
|
|
}
|
|
test = -1.0e20;
|
|
}
|
|
|
|
/*
|
|
* NC = number of components is in the vcs.h common block
|
|
* This call to BASOPT doesn't calculate the stoichiometric
|
|
* reaction matrix.
|
|
*/
|
|
std::vector<double> awSpace(m_numSpeciesTot + (m_numElemConstraints + 2)*(m_numElemConstraints), 0.0);
|
|
aw = VCS_DATA_PTR(awSpace);
|
|
if (aw == NULL) {
|
|
plogf("vcs_prep_oneTime: failed to get memory: global bailout\n");
|
|
return VCS_NOMEMORY;
|
|
}
|
|
sa = aw + m_numSpeciesTot;
|
|
sm = sa + m_numElemConstraints;
|
|
ss = sm + (m_numElemConstraints)*(m_numElemConstraints);
|
|
retn = vcs_basopt(true, aw, sa, sm, ss, test, &conv);
|
|
if (retn != VCS_SUCCESS) {
|
|
plogf("vcs_prep_oneTime:");
|
|
plogf(" Determination of number of components failed: %d\n",
|
|
retn);
|
|
plogf(" Global Bailout!\n");
|
|
return retn;
|
|
}
|
|
|
|
if (m_numSpeciesTot >= m_numComponents) {
|
|
m_numRxnTot = m_numRxnRdc = m_numSpeciesTot - m_numComponents;
|
|
for (i = 0; i < m_numRxnRdc; ++i) {
|
|
m_indexRxnToSpecies[i] = m_numComponents + i;
|
|
}
|
|
} else {
|
|
m_numRxnTot = m_numRxnRdc = 0;
|
|
}
|
|
|
|
/*
|
|
* The elements might need to be rearranged.
|
|
*/
|
|
awSpace.resize(m_numElemConstraints + (m_numElemConstraints + 2)*(m_numElemConstraints), 0.0);
|
|
aw = VCS_DATA_PTR(awSpace);
|
|
sa = aw + m_numElemConstraints;
|
|
sm = sa + m_numElemConstraints;
|
|
ss = sm + (m_numElemConstraints)*(m_numElemConstraints);
|
|
retn = vcs_elem_rearrange(aw, sa, sm, ss);
|
|
if (retn != VCS_SUCCESS) {
|
|
plogf("vcs_prep_oneTime:");
|
|
plogf(" Determination of element reordering failed: %d\n",
|
|
retn);
|
|
plogf(" Global Bailout!\n");
|
|
return retn;
|
|
}
|
|
|
|
// If we mucked up the solution unknowns because they were all
|
|
// zero to start with, set them back to zero here
|
|
if (modifiedSoln) {
|
|
for (kspec = 0; kspec < m_numSpeciesTot; ++kspec) {
|
|
m_molNumSpecies_old[kspec] = 0.0;
|
|
}
|
|
}
|
|
return VCS_SUCCESS;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
// Prepare the object for re-solution
|
|
/*
|
|
* This routine is mostly concerned with changing the private data
|
|
* to be consistent with that needed for solution. It is called for
|
|
* every invocation of the vcs_solve() except for the cleanup invocation.
|
|
*
|
|
* Tasks:
|
|
* 1) Initialization of arrays to zero.
|
|
* 2) Calculate total number of moles in all phases
|
|
*
|
|
* return code
|
|
* VCS_SUCCESS = everything went OK
|
|
* VCS_PUB_BAD = There is an irreconcilable difference in the
|
|
* public data structure from when the problem was
|
|
* initially set up.
|
|
*/
|
|
int VCS_SOLVE::vcs_prep()
|
|
{
|
|
/*
|
|
* Initialize various arrays in the data to zero
|
|
*/
|
|
vcs_vdzero(m_feSpecies_old, m_numSpeciesTot);
|
|
vcs_vdzero(m_feSpecies_new, m_numSpeciesTot);
|
|
vcs_vdzero(m_molNumSpecies_new, m_numSpeciesTot);
|
|
vcs_dzero(&(m_deltaMolNumPhase[0][0]), m_numSpeciesTot * m_numPhases);
|
|
vcs_izero(&(m_phaseParticipation[0][0]), m_numSpeciesTot * m_numPhases);
|
|
vcs_dzero(VCS_DATA_PTR(m_deltaPhaseMoles), m_numPhases);
|
|
vcs_dzero(VCS_DATA_PTR(m_tPhaseMoles_new), m_numPhases);
|
|
/*
|
|
* Calculate the total number of moles in all phases.
|
|
*/
|
|
vcs_tmoles();
|
|
return VCS_SUCCESS;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
// In this routine, we check for things that will cause the algorithm
|
|
// to fail.
|
|
/*
|
|
* We check to see if the problem is well posed. If it is not, we return
|
|
* false and print out error conditions.
|
|
*
|
|
* Current there is one condition. If all the element abundances are
|
|
* zero, the algorithm will fail
|
|
*
|
|
* @param vprob VCS_PROB pointer to the definition of the equilibrium
|
|
* problem
|
|
*
|
|
* @return If true, the problem is well-posed. If false, the problem
|
|
* is not well posed.
|
|
*/
|
|
bool VCS_SOLVE::vcs_wellPosed(VCS_PROB* vprob)
|
|
{
|
|
double sum = 0.0;
|
|
for (size_t e = 0; e < vprob->ne; e++) {
|
|
sum = sum + vprob->gai[e];
|
|
}
|
|
if (sum < 1.0E-20) {
|
|
plogf("vcs_wellPosed: Element abundance is close to zero\n");
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
}
|