cantera/src/equil/vcs_solve.cpp

958 lines
30 KiB
C++

/*!
* @file vcs_solve.cpp Implementation file for the internal class that holds
* the problem.
*/
/*
* 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/base/ctexceptions.h"
#include "cantera/base/stringUtils.h"
#include "cantera/equil/vcs_prob.h"
#include "cantera/equil/vcs_VolPhase.h"
#include "cantera/equil/vcs_species_thermo.h"
#include "cantera/base/clockWC.h"
using namespace std;
namespace Cantera
{
int vcs_timing_print_lvl = 1;
VCS_SOLVE::VCS_SOLVE() :
NSPECIES0(0),
NPHASE0(0),
m_numSpeciesTot(0),
m_numElemConstraints(0),
m_numComponents(0),
m_numRxnTot(0),
m_numSpeciesRdc(0),
m_numRxnRdc(0),
m_numRxnMinorZeroed(0),
m_numPhases(0),
m_doEstimateEquil(0),
m_totalMolNum(0.0),
m_temperature(0.0),
m_pressurePA(0.0),
m_tolmaj(0.0),
m_tolmin(0.0),
m_tolmaj2(0.0),
m_tolmin2(0.0),
m_unitsState(VCS_DIMENSIONAL_G),
m_totalMoleScale(1.0),
m_useActCoeffJac(0),
m_totalVol(0.0),
m_Faraday_dim(ElectronCharge * Avogadro),
m_VCount(0),
m_debug_print_lvl(0),
m_timing_print_lvl(1),
m_VCS_UnitsFormat(VCS_UNITS_UNITLESS)
{
}
void VCS_SOLVE::vcs_initSizes(const size_t nspecies0, const size_t nelements,
const size_t nphase0)
{
if (NSPECIES0 != 0) {
if ((nspecies0 != NSPECIES0) || (nelements != m_numElemConstraints) || (nphase0 != NPHASE0)) {
vcs_delete_memory();
} else {
return;
}
}
NSPECIES0 = nspecies0;
NPHASE0 = nphase0;
m_numSpeciesTot = nspecies0;
m_numElemConstraints = nelements;
m_numComponents = nelements;
string ser = "VCS_SOLVE: ERROR:\n\t";
if (nspecies0 <= 0) {
plogf("%s Number of species is nonpositive\n", ser);
throw CanteraError("VCS_SOLVE()", ser +
" Number of species is nonpositive\n");
}
if (nelements <= 0) {
plogf("%s Number of elements is nonpositive\n", ser);
throw CanteraError("VCS_SOLVE()", ser +
" Number of species is nonpositive\n");
}
if (nphase0 <= 0) {
plogf("%s Number of phases is nonpositive\n", ser);
throw CanteraError("VCS_SOLVE()", ser +
" Number of species is nonpositive\n");
}
m_VCS_UnitsFormat = VCS_UNITS_UNITLESS;
/*
* We will initialize sc[] to note the fact that it needs to be
* filled with meaningful information.
*/
m_stoichCoeffRxnMatrix.resize(nelements, nspecies0, 0.0);
m_scSize.resize(nspecies0, 0.0);
m_spSize.resize(nspecies0, 1.0);
m_SSfeSpecies.resize(nspecies0, 0.0);
m_feSpecies_new.resize(nspecies0, 0.0);
m_molNumSpecies_old.resize(nspecies0, 0.0);
m_speciesUnknownType.resize(nspecies0, VCS_SPECIES_TYPE_MOLNUM);
m_deltaMolNumPhase.resize(nphase0, nspecies0, 0.0);
m_phaseParticipation.resize(nphase0, nspecies0, 0);
m_phasePhi.resize(nphase0, 0.0);
m_molNumSpecies_new.resize(nspecies0, 0.0);
m_deltaGRxn_new.resize(nspecies0, 0.0);
m_deltaGRxn_old.resize(nspecies0, 0.0);
m_deltaGRxn_Deficient.resize(nspecies0, 0.0);
m_deltaGRxn_tmp.resize(nspecies0, 0.0);
m_deltaMolNumSpecies.resize(nspecies0, 0.0);
m_feSpecies_old.resize(nspecies0, 0.0);
m_elemAbundances.resize(nelements, 0.0);
m_elemAbundancesGoal.resize(nelements, 0.0);
m_tPhaseMoles_old.resize(nphase0, 0.0);
m_tPhaseMoles_new.resize(nphase0, 0.0);
m_deltaPhaseMoles.resize(nphase0, 0.0);
m_TmpPhase.resize(nphase0, 0.0);
m_TmpPhase2.resize(nphase0, 0.0);
m_formulaMatrix.resize(nspecies0, nelements);
TPhInertMoles.resize(nphase0, 0.0);
/*
* ind[] is an index variable that keep track of solution vector
* rotations.
*/
m_speciesMapIndex.resize(nspecies0, 0);
m_speciesLocalPhaseIndex.resize(nspecies0, 0);
/*
* IndEl[] is an index variable that keep track of element vector
* rotations.
*/
m_elementMapIndex.resize(nelements, 0);
/*
* ir[] is an index vector that keeps track of the irxn to species
* mapping. We can't fill it in until we know the number of c
* components in the problem
*/
m_indexRxnToSpecies.resize(nspecies0, 0);
/* Initialize all species to be major species */
m_speciesStatus.resize(nspecies0, 1);
m_SSPhase.resize(2*nspecies0, 0);
m_phaseID.resize(nspecies0, 0);
m_numElemConstraints = nelements;
m_elementName.resize(nelements, std::string(""));
m_speciesName.resize(nspecies0, std::string(""));
m_elType.resize(nelements, VCS_ELEM_TYPE_ABSPOS);
m_elementActive.resize(nelements, 1);
/*
* Malloc space for activity coefficients for all species
* -> Set it equal to one.
*/
m_actConventionSpecies.resize(nspecies0, 0);
m_phaseActConvention.resize(nphase0, 0);
m_lnMnaughtSpecies.resize(nspecies0, 0.0);
m_actCoeffSpecies_new.resize(nspecies0, 1.0);
m_actCoeffSpecies_old.resize(nspecies0, 1.0);
m_wtSpecies.resize(nspecies0, 0.0);
m_chargeSpecies.resize(nspecies0, 0.0);
m_speciesThermoList.resize(nspecies0, (VCS_SPECIES_THERMO*)0);
/*
* Malloc Phase Info
*/
m_VolPhaseList.resize(nphase0, 0);
for (size_t iph = 0; iph < nphase0; iph++) {
m_VolPhaseList[iph] = new vcs_VolPhase(this);
}
/*
* For Future expansion
*/
m_useActCoeffJac = true;
if (m_useActCoeffJac) {
m_np_dLnActCoeffdMolNum.resize(nspecies0, nspecies0, 0.0);
}
m_PMVolumeSpecies.resize(nspecies0, 0.0);
/*
* Malloc space for counters kept within vcs
*
*/
m_VCount = new VCS_COUNTERS();
vcs_counters_init(1);
if (vcs_timing_print_lvl == 0) {
m_timing_print_lvl = 0;
}
return;
}
VCS_SOLVE::~VCS_SOLVE()
{
vcs_delete_memory();
}
void VCS_SOLVE::vcs_delete_memory()
{
size_t nspecies = m_numSpeciesTot;
for (size_t j = 0; j < m_numPhases; j++) {
delete m_VolPhaseList[j];
m_VolPhaseList[j] = 0;
}
for (size_t j = 0; j < nspecies; j++) {
delete m_speciesThermoList[j];
m_speciesThermoList[j] = 0;
}
delete m_VCount;
m_VCount = 0;
NSPECIES0 = 0;
NPHASE0 = 0;
m_numElemConstraints = 0;
m_numComponents = 0;
}
int VCS_SOLVE::vcs(VCS_PROB* vprob, int ifunc, int ipr, int ip1, int maxit)
{
int retn = 0, iconv = 0;
clockWC tickTock;
int iprintTime = std::max(ipr, ip1);
iprintTime = std::min(iprintTime, m_timing_print_lvl);
if (ifunc > 2) {
plogf("vcs: Unrecognized value of ifunc, %d: bailing!\n",
ifunc);
return VCS_PUB_BAD;
}
if (ifunc == 0) {
/*
* This function is called to create the private data
* using the public data.
*/
size_t nspecies0 = vprob->nspecies + 10;
size_t nelements0 = vprob->ne;
size_t nphase0 = vprob->NPhase;
vcs_initSizes(nspecies0, nelements0, nphase0);
if (retn != 0) {
plogf("vcs_priv_alloc returned a bad status, %d: bailing!\n",
retn);
return retn;
}
/*
* This function is called to copy the public data
* and the current problem specification
* into the current object's data structure.
*/
retn = vcs_prob_specifyFully(vprob);
if (retn != 0) {
plogf("vcs_pub_to_priv returned a bad status, %d: bailing!\n",
retn);
return retn;
}
/*
* Prep the problem data
* - adjust the identity of any phases
* - determine the number of components in the problem
*/
retn = vcs_prep_oneTime(ip1);
if (retn != 0) {
plogf("vcs_prep_oneTime returned a bad status, %d: bailing!\n",
retn);
return retn;
}
}
if (ifunc == 1) {
/*
* This function is called to copy the current problem
* into the current object's data structure.
*/
retn = vcs_prob_specify(vprob);
if (retn != 0) {
plogf("vcs_prob_specify returned a bad status, %d: bailing!\n",
retn);
return retn;
}
}
if (ifunc != 2) {
/*
* Prep the problem data for this particular instantiation of
* the problem
*/
retn = vcs_prep();
if (retn != VCS_SUCCESS) {
plogf("vcs_prep returned a bad status, %d: bailing!\n", retn);
return retn;
}
/*
* Check to see if the current problem is well posed.
*/
if (!vcs_wellPosed(vprob)) {
plogf("vcs has determined the problem is not well posed: Bailing\n");
return VCS_PUB_BAD;
}
/*
* Once we have defined the global internal data structure defining
* the problem, then we go ahead and solve the problem.
*
* (right now, all we do is solve fixed T, P problems.
* Methods for other problem types will go in at this level.
* For example, solving for fixed T, V problems will involve
* a 2x2 Newton's method, using loops over vcs_TP() to
* calculate the residual and Jacobian)
*/
iconv = vcs_TP(ipr, ip1, maxit, vprob->T, vprob->PresPA);
/*
* If requested to print anything out, go ahead and do so;
*/
if (ipr > 0) {
vcs_report(iconv);
}
/*
* Copy the results of the run back to the VCS_PROB structure,
* which is returned to the user.
*/
vcs_prob_update(vprob);
}
/*
* Report on the time if requested to do so
*/
double te = tickTock.secondsWC();
m_VCount->T_Time_vcs += te;
if (iprintTime > 0) {
vcs_TCounters_report(m_timing_print_lvl);
}
/*
* Now, destroy the private data, if requested to do so
*
* FILL IN
*/
if (iconv < 0) {
plogf("ERROR: FAILURE its = %d!\n", m_VCount->Its);
} else if (iconv == 1) {
plogf("WARNING: RANGE SPACE ERROR encountered\n");
}
return iconv;
}
int VCS_SOLVE::vcs_prob_specifyFully(const VCS_PROB* pub)
{
const char* ser =
"vcs_pub_to_priv ERROR :ill defined interface -> bailout:\n\t";
/*
* First Check to see whether we have room for the current problem
* size
*/
size_t nspecies = pub->nspecies;
if (NSPECIES0 < nspecies) {
plogf("%sPrivate Data is dimensioned too small\n", ser);
return VCS_PUB_BAD;
}
size_t nph = pub->NPhase;
if (NPHASE0 < nph) {
plogf("%sPrivate Data is dimensioned too small\n", ser);
return VCS_PUB_BAD;
}
size_t nelements = pub->ne;
if (m_numElemConstraints < nelements) {
plogf("%sPrivate Data is dimensioned too small\n", ser);
return VCS_PUB_BAD;
}
/*
* OK, We have room. Now, transfer the integer numbers
*/
m_numElemConstraints = nelements;
m_numSpeciesTot = nspecies;
m_numSpeciesRdc = m_numSpeciesTot;
/*
* nc = number of components -> will be determined later.
* but set it to its maximum possible value here.
*/
m_numComponents = nelements;
/*
* m_numRxnTot = number of noncomponents, also equal to the
* number of reactions
* Note, it's possible that the number of elements is greater than
* the number of species. In that case set the number of reactions
* to zero.
*/
if (nelements > nspecies) {
m_numRxnTot = 0;
} else {
m_numRxnTot = nspecies - nelements;
}
m_numRxnRdc = m_numRxnTot;
/*
* number of minor species rxn -> all species rxn are major at the start.
*/
m_numRxnMinorZeroed = 0;
/*
* NPhase = number of phases
*/
m_numPhases = nph;
#ifdef DEBUG_MODE
m_debug_print_lvl = pub->vcs_debug_print_lvl;
#else
m_debug_print_lvl = std::min(2, pub->vcs_debug_print_lvl);
#endif
/*
* FormulaMatrix[] -> Copy the formula matrix over
*/
for (size_t i = 0; i < nspecies; i++) {
bool nonzero = false;
for (size_t j = 0; j < nelements; j++) {
if (pub->FormulaMatrix(i,j) != 0.0) {
nonzero = true;
}
m_formulaMatrix(i,j) = pub->FormulaMatrix(i,j);
}
if (!nonzero) {
plogf("vcs_prob_specifyFully:: species %d %s has a zero formula matrix!\n", i,
pub->SpName[i]);
return VCS_PUB_BAD;
}
}
/*
* Copy over the species molecular weights
*/
m_wtSpecies = pub->WtSpecies;
/*
* Copy over the charges
*/
m_chargeSpecies = pub->Charge;
/*
* Malloc and Copy the VCS_SPECIES_THERMO structures
*
*/
for (size_t kspec = 0; kspec < nspecies; kspec++) {
delete m_speciesThermoList[kspec];
VCS_SPECIES_THERMO* spf = pub->SpeciesThermo[kspec];
m_speciesThermoList[kspec] = spf->duplMyselfAsVCS_SPECIES_THERMO();
if (m_speciesThermoList[kspec] == NULL) {
plogf(" duplMyselfAsVCS_SPECIES_THERMO returned an error!\n");
return VCS_PUB_BAD;
}
}
/*
* Copy the species unknown type
*/
m_speciesUnknownType = pub->SpeciesUnknownType;
/*
* iest => Do we have an initial estimate of the species mole numbers ?
*/
m_doEstimateEquil = pub->iest;
/*
* w[] -> Copy the equilibrium mole number estimate if it exists.
*/
if (pub->w.size() != 0) {
m_molNumSpecies_old = pub->w;
} else {
m_doEstimateEquil = -1;
m_molNumSpecies_old.assign(m_molNumSpecies_old.size(), 0.0);
}
/*
* Formulate the Goal Element Abundance Vector
*/
if (pub->gai.size() != 0) {
for (size_t i = 0; i < nelements; i++) {
m_elemAbundancesGoal[i] = pub->gai[i];
if (pub->m_elType[i] == VCS_ELEM_TYPE_LATTICERATIO && m_elemAbundancesGoal[i] < 1.0E-10) {
m_elemAbundancesGoal[i] = 0.0;
}
}
} else {
if (m_doEstimateEquil == 0) {
double sum = 0;
for (size_t j = 0; j < nelements; j++) {
m_elemAbundancesGoal[j] = 0.0;
for (size_t kspec = 0; kspec < nspecies; kspec++) {
if (m_speciesUnknownType[kspec] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) {
sum += m_molNumSpecies_old[kspec];
m_elemAbundancesGoal[j] += m_formulaMatrix(kspec,j) * m_molNumSpecies_old[kspec];
}
}
if (pub->m_elType[j] == VCS_ELEM_TYPE_LATTICERATIO && m_elemAbundancesGoal[j] < 1.0E-10 * sum) {
m_elemAbundancesGoal[j] = 0.0;
}
}
} else {
plogf("%sElement Abundances, m_elemAbundancesGoal[], not specified\n", ser);
return VCS_PUB_BAD;
}
}
/*
* zero out values that will be filled in later
*/
/*
* TPhMoles[] -> Untouched here. These will be filled in vcs_prep.c
* TPhMoles1[]
* DelTPhMoles[]
*
* T, Pres, copy over here
*/
if (pub->T > 0.0) {
m_temperature = pub->T;
} else {
m_temperature = 293.15;
}
if (pub->PresPA > 0.0) {
m_pressurePA = pub->PresPA;
} else {
m_pressurePA = OneAtm;
}
/*
* TPhInertMoles[] -> must be copied over here
*/
for (size_t iph = 0; iph < nph; iph++) {
vcs_VolPhase* Vphase = pub->VPhaseList[iph];
TPhInertMoles[iph] = Vphase->totalMolesInert();
}
/*
* if__ : Copy over the units for the chemical potential
*/
m_VCS_UnitsFormat = pub->m_VCS_UnitsFormat;
/*
* tolerance requirements -> copy them over here and later
*/
m_tolmaj = pub->tolmaj;
m_tolmin = pub->tolmin;
m_tolmaj2 = 0.01 * m_tolmaj;
m_tolmin2 = 0.01 * m_tolmin;
/*
* m_speciesIndexVector[] is an index variable that keep track
* of solution vector rotations.
*/
for (size_t i = 0; i < nspecies; i++) {
m_speciesMapIndex[i] = i;
}
/*
* IndEl[] is an index variable that keep track of element vector
* rotations.
*/
for (size_t i = 0; i < nelements; i++) {
m_elementMapIndex[i] = i;
}
/*
* Define all species to be major species, initially.
*/
for (size_t i = 0; i < nspecies; i++) {
m_speciesStatus[i] = VCS_SPECIES_MAJOR;
}
/*
* PhaseID: Fill in the species to phase mapping
* -> Check for bad values at the same time.
*/
if (pub->PhaseID.size() != 0) {
std::vector<size_t> numPhSp(nph, 0);
for (size_t kspec = 0; kspec < nspecies; kspec++) {
size_t iph = pub->PhaseID[kspec];
if (iph >= nph) {
plogf("%sSpecies to Phase Mapping, PhaseID, has a bad value\n",
ser);
plogf("\tPhaseID[%d] = %d\n", kspec, iph);
plogf("\tAllowed values: 0 to %d\n", nph - 1);
return VCS_PUB_BAD;
}
m_phaseID[kspec] = pub->PhaseID[kspec];
m_speciesLocalPhaseIndex[kspec] = numPhSp[iph];
numPhSp[iph]++;
}
for (size_t iph = 0; iph < nph; iph++) {
vcs_VolPhase* Vphase = pub->VPhaseList[iph];
if (numPhSp[iph] != Vphase->nSpecies()) {
plogf("%sNumber of species in phase %d, %s, doesn't match\n",
ser, iph, Vphase->PhaseName);
return VCS_PUB_BAD;
}
}
} else {
if (m_numPhases == 1) {
for (size_t kspec = 0; kspec < nspecies; kspec++) {
m_phaseID[kspec] = 0;
m_speciesLocalPhaseIndex[kspec] = kspec;
}
} else {
plogf("%sSpecies to Phase Mapping, PhaseID, is not defined\n", ser);
return VCS_PUB_BAD;
}
}
/*
* Copy over the element types
*/
m_elType.resize(nelements, VCS_ELEM_TYPE_ABSPOS);
m_elementActive.resize(nelements, 1);
/*
* Copy over the element names and types
*/
for (size_t i = 0; i < nelements; i++) {
m_elementName[i] = pub->ElName[i];
m_elType[i] = pub->m_elType[i];
m_elementActive[i] = pub->ElActive[i];
if (!strncmp(m_elementName[i].c_str(), "cn_", 3)) {
m_elType[i] = VCS_ELEM_TYPE_CHARGENEUTRALITY;
if (pub->m_elType[i] != VCS_ELEM_TYPE_CHARGENEUTRALITY) {
throw CanteraError("VCS_SOLVE::vcs_prob_specifyFully",
"we have an inconsistency!");
}
}
}
for (size_t i = 0; i < nelements; i++) {
if (m_elType[i] == VCS_ELEM_TYPE_CHARGENEUTRALITY) {
if (m_elemAbundancesGoal[i] != 0.0) {
if (fabs(m_elemAbundancesGoal[i]) > 1.0E-9) {
throw CanteraError("VCS_SOLVE::vcs_prob_specifyFully",
"Charge neutrality condition " + m_elementName[i] +
" is signicantly nonzero, " + fp2str(m_elemAbundancesGoal[i]) +
". Giving up");
} else {
if (m_debug_print_lvl >= 2) {
plogf("Charge neutrality condition %s not zero, %g. Setting it zero\n",
m_elementName[i], m_elemAbundancesGoal[i]);
}
m_elemAbundancesGoal[i] = 0.0;
}
}
}
}
/*
* Copy over the species names
*/
for (size_t i = 0; i < nspecies; i++) {
m_speciesName[i] = pub->SpName[i];
}
/*
* Copy over all of the phase information
* Use the object's assignment operator
*/
for (size_t iph = 0; iph < nph; iph++) {
*m_VolPhaseList[iph] = *pub->VPhaseList[iph];
/*
* Fix up the species thermo pointer in the vcs_SpeciesThermo object
* It should point to the species thermo pointer in the private
* data space.
*/
vcs_VolPhase* Vphase = m_VolPhaseList[iph];
for (size_t k = 0; k < Vphase->nSpecies(); k++) {
vcs_SpeciesProperties* sProp = Vphase->speciesProperty(k);
size_t kT = Vphase->spGlobalIndexVCS(k);
sProp->SpeciesThermo = m_speciesThermoList[kT];
}
}
/*
* Specify the Activity Convention information
*/
for (size_t iph = 0; iph < nph; iph++) {
vcs_VolPhase* Vphase = m_VolPhaseList[iph];
m_phaseActConvention[iph] = Vphase->p_activityConvention;
if (Vphase->p_activityConvention != 0) {
/*
* We assume here that species 0 is the solvent.
* The solvent isn't on a unity activity basis
* The activity for the solvent assumes that the
* it goes to one as the species mole fraction goes to
* one; i.e., it's really on a molarity framework.
* So SpecLnMnaught[iSolvent] = 0.0, and the
* loop below starts at 1, not 0.
*/
size_t iSolvent = Vphase->spGlobalIndexVCS(0);
double mnaught = m_wtSpecies[iSolvent] / 1000.;
for (size_t k = 1; k < Vphase->nSpecies(); k++) {
size_t kspec = Vphase->spGlobalIndexVCS(k);
m_actConventionSpecies[kspec] = Vphase->p_activityConvention;
m_lnMnaughtSpecies[kspec] = log(mnaught);
}
}
}
/*
* Copy the title info
*/
if (pub->Title.size() == 0) {
m_title = "Unspecified Problem Title";
} else {
m_title = pub->Title;
}
/*
* Copy the volume info
*/
m_totalVol = pub->Vol;
if (m_PMVolumeSpecies.size() != 0) {
m_PMVolumeSpecies = pub->VolPM;
}
/*
* Return the success flag
*/
return VCS_SUCCESS;
}
int VCS_SOLVE::vcs_prob_specify(const VCS_PROB* pub)
{
string yo("vcs_prob_specify ERROR: ");
int retn = VCS_SUCCESS;
m_temperature = pub->T;
m_pressurePA = pub->PresPA;
m_VCS_UnitsFormat = pub->m_VCS_UnitsFormat;
m_doEstimateEquil = pub->iest;
m_totalVol = pub->Vol;
m_tolmaj = pub->tolmaj;
m_tolmin = pub->tolmin;
m_tolmaj2 = 0.01 * m_tolmaj;
m_tolmin2 = 0.01 * m_tolmin;
for (size_t kspec = 0; kspec < m_numSpeciesTot; ++kspec) {
size_t k = m_speciesMapIndex[kspec];
m_molNumSpecies_old[kspec] = pub->w[k];
m_molNumSpecies_new[kspec] = pub->mf[k];
m_feSpecies_old[kspec] = pub->m_gibbsSpecies[k];
}
/*
* Transfer the element abundance goals to the solve object
*/
for (size_t i = 0; i < m_numElemConstraints; i++) {
size_t j = m_elementMapIndex[i];
m_elemAbundancesGoal[i] = pub->gai[j];
}
/*
* Try to do the best job at guessing at the title
*/
if (pub->Title.size() == 0) {
if (m_title.size() == 0) {
m_title = "Unspecified Problem Title";
}
} else {
m_title = pub->Title;
}
/*
* Copy over the phase information.
* -> For each entry in the phase structure, determine
* if that entry can change from its initial value
* Either copy over the new value or create an error
* condition.
*/
bool status_change = false;
for (size_t iph = 0; iph < m_numPhases; iph++) {
vcs_VolPhase* vPhase = m_VolPhaseList[iph];
vcs_VolPhase* pub_phase_ptr = pub->VPhaseList[iph];
if (vPhase->VP_ID_ != pub_phase_ptr->VP_ID_) {
plogf("%sPhase numbers have changed:%d %d\n",
yo, vPhase->VP_ID_, pub_phase_ptr->VP_ID_);
retn = VCS_PUB_BAD;
}
if (vPhase->m_singleSpecies != pub_phase_ptr->m_singleSpecies) {
plogf("%sSingleSpecies value have changed:%d %d\n",
yo, vPhase->m_singleSpecies, pub_phase_ptr->m_singleSpecies);
retn = VCS_PUB_BAD;
}
if (vPhase->m_gasPhase != pub_phase_ptr->m_gasPhase) {
plogf("%sGasPhase value have changed:%d %d\n",
yo, vPhase->m_gasPhase, pub_phase_ptr->m_gasPhase);
retn = VCS_PUB_BAD;
}
vPhase->m_eqnState = pub_phase_ptr->m_eqnState;
if (vPhase->nSpecies() != pub_phase_ptr->nSpecies()) {
plogf("%sNVolSpecies value have changed:%d %d\n",
yo, vPhase->nSpecies(), pub_phase_ptr->nSpecies());
retn = VCS_PUB_BAD;
}
if (vPhase->PhaseName != pub_phase_ptr->PhaseName) {
plogf("%sPhaseName value have changed:%s %s\n",
yo, vPhase->PhaseName, pub_phase_ptr->PhaseName);
retn = VCS_PUB_BAD;
}
if (vPhase->totalMolesInert() != pub_phase_ptr->totalMolesInert()) {
status_change = true;
}
/*
* Copy over the number of inert moles if it has changed.
*/
TPhInertMoles[iph] = pub_phase_ptr->totalMolesInert();
vPhase->setTotalMolesInert(pub_phase_ptr->totalMolesInert());
if (TPhInertMoles[iph] > 0.0) {
vPhase->setExistence(2);
vPhase->m_singleSpecies = false;
}
/*
* Copy over the interfacial potential
*/
double phi = pub_phase_ptr->electricPotential();
vPhase->setElectricPotential(phi);
}
if (status_change) {
vcs_SSPhase();
}
/*
* Calculate the total number of moles in all phases.
*/
vcs_tmoles();
return retn;
}
int VCS_SOLVE::vcs_prob_update(VCS_PROB* pub)
{
size_t k1 = 0;
vcs_tmoles();
m_totalVol = vcs_VolTotal(m_temperature, m_pressurePA,
&m_molNumSpecies_old[0], &m_PMVolumeSpecies[0]);
for (size_t i = 0; i < m_numSpeciesTot; ++i) {
/*
* Find the index of I in the index vector, m_speciesIndexVector[].
* Call it K1 and continue.
*/
for (size_t j = 0; j < m_numSpeciesTot; ++j) {
k1 = j;
if (m_speciesMapIndex[j] == i) {
break;
}
}
/*
* - Switch the species data back from K1 into I
*/
if (pub->SpeciesUnknownType[i] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) {
pub->w[i] = m_molNumSpecies_old[k1];
} else {
pub->w[i] = 0.0;
}
pub->m_gibbsSpecies[i] = m_feSpecies_old[k1];
pub->VolPM[i] = m_PMVolumeSpecies[k1];
}
pub->T = m_temperature;
pub->PresPA = m_pressurePA;
pub->Vol = m_totalVol;
size_t kT = 0;
for (size_t iph = 0; iph < pub->NPhase; iph++) {
vcs_VolPhase* pubPhase = pub->VPhaseList[iph];
vcs_VolPhase* vPhase = m_VolPhaseList[iph];
pubPhase->setTotalMolesInert(vPhase->totalMolesInert());
pubPhase->setTotalMoles(vPhase->totalMoles());
pubPhase->setElectricPotential(vPhase->electricPotential());
double sumMoles = pubPhase->totalMolesInert();
pubPhase->setMoleFractionsState(vPhase->totalMoles(),
&vPhase->moleFractions()[0],
VCS_STATECALC_TMP);
const vector_fp & mfVector = pubPhase->moleFractions();
for (size_t k = 0; k < pubPhase->nSpecies(); k++) {
kT = pubPhase->spGlobalIndexVCS(k);
pub->mf[kT] = mfVector[k];
if (pubPhase->phiVarIndex() == k) {
k1 = vPhase->spGlobalIndexVCS(k);
double tmp = m_molNumSpecies_old[k1];
if (! vcs_doubleEqual(pubPhase->electricPotential() , tmp)) {
throw CanteraError("VCS_SOLVE::vcs_prob_update",
"We have an inconsistency in voltage, " +
fp2str(pubPhase->electricPotential()) + " " +
fp2str(tmp));
}
}
if (! vcs_doubleEqual(pub->mf[kT], vPhase->molefraction(k))) {
throw CanteraError("VCS_SOLVE::vcs_prob_update",
"We have an inconsistency in mole fraction, " +
fp2str(pub->mf[kT]) + " " + fp2str(vPhase->molefraction(k)));
}
if (pubPhase->speciesUnknownType(k) != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) {
sumMoles += pub->w[kT];
}
}
if (! vcs_doubleEqual(sumMoles, vPhase->totalMoles())) {
throw CanteraError("VCS_SOLVE::vcs_prob_update",
"We have an inconsistency in total moles, " +
fp2str(sumMoles) + " " + fp2str(pubPhase->totalMoles()));
}
}
pub->m_Iterations = m_VCount->Its;
pub->m_NumBasisOptimizations = m_VCount->Basis_Opts;
return VCS_SUCCESS;
}
void VCS_SOLVE::vcs_counters_init(int ifunc)
{
m_VCount->Its = 0;
m_VCount->Basis_Opts = 0;
m_VCount->Time_vcs_TP = 0.0;
m_VCount->Time_basopt = 0.0;
if (ifunc) {
m_VCount->T_Its = 0;
m_VCount->T_Basis_Opts = 0;
m_VCount->T_Calls_Inest = 0;
m_VCount->T_Calls_vcs_TP = 0;
m_VCount->T_Time_vcs_TP = 0.0;
m_VCount->T_Time_basopt = 0.0;
m_VCount->T_Time_inest = 0.0;
m_VCount->T_Time_vcs = 0.0;
}
}
double VCS_SOLVE::vcs_VolTotal(const double tkelvin, const double pres,
const double w[], double volPM[])
{
double VolTot = 0.0;
for (size_t iphase = 0; iphase < m_numPhases; iphase++) {
vcs_VolPhase* Vphase = m_VolPhaseList[iphase];
Vphase->setState_TP(tkelvin, pres);
Vphase->setMolesFromVCS(VCS_STATECALC_OLD, w);
double Volp = Vphase->sendToVCS_VolPM(volPM);
VolTot += Volp;
}
return VolTot;
}
}