Significant Update to the Equilibrium Solver

Added a capability to solve for the mathematical condition for the
birth of a multispecies phase. Added the logic into the algorithm.
This commit is contained in:
Harry Moffat 2009-01-22 22:27:07 +00:00
parent f5e6b47e7b
commit ef278fc885
8 changed files with 1159 additions and 461 deletions

View file

@ -1107,6 +1107,7 @@ namespace VCSnonideal {
resize(VP_ID, nsp, nelem, PhaseName.c_str());
}
TP_ptr->getMoleFractions(VCS_DATA_PTR(Xmol));
fractionCreationDelta_ = Xmol;
_updateMoleFractionDependencies();
/*

View file

@ -104,7 +104,7 @@ namespace VCSnonideal {
//! Cutoff relative moles below which a phase is deleted
//! from the equilibrium problem.
#ifndef VCS_DELETE_PHASE_CUTOFF
#define VCS_DELETE_PHASE_CUTOFF 1.0e-11
#define VCS_DELETE_PHASE_CUTOFF 1.0e-12
#endif
//@}

View file

@ -22,90 +22,683 @@
using namespace std;
namespace VCSnonideal {
// Utility function that evaluates whether a phase can be popped
// into existence
/*
* @param iphasePop id of the phase, which is currently zeroed,
*
* @return Returns true if the phase can come into existence
* and false otherwise.
*/
bool VCS_SOLVE::vcs_popPhasePossible(const int iphasePop) const {
vcs_VolPhase *Vphase = m_VolPhaseList[iphasePop];
#ifdef DEBUG_MODE
int existence = Vphase->exists();
if (existence > 0) {
printf("ERROR vcs_popPhasePossible called for a phase that exists!");
exit(-1);
}
#endif
/*
* section to do damping of the m_deltaMolNumSpecies[]
*/
for (int k = 0; k < Vphase->nSpecies(); k++) {
int kspec = Vphase->spGlobalIndexVCS(k);
int irxn = kspec - m_numComponents;
if (irxn >= 0) {
for (int j = 0; j < m_numComponents; ++j) {
if (m_elType[j] == VCS_ELEM_TYPE_ABSPOS) {
double stoicC = m_stoichCoeffRxnMatrix[irxn][j];
if (stoicC != 0.0) {
double negChangeComp = - stoicC * 1.0;
if (negChangeComp > 0.0) {
// TODO: We may have to come up with a tolerance here
if (m_molNumSpecies_old[j] <= 1.0E-300) {
#ifdef DEBUG_MODE
if (m_debug_print_lvl >= 3) {
plogf(" --- vcs_popPhasePosssible() Phase %d (%s) can't be popped\n", iphasePop,
Vphase->PhaseName.c_str());
plogf(" --- Component %d (%s)will go negative\n", j, m_speciesName[j].c_str());
}
#endif
return false;
}
}
}
}
}
}
}
return true;
}
// Decision as to whether a phase pops back into existence
/*
* @return returns the phase id of the phase that pops back into
* existence. Returns -1 if there are no phases
*/
int VCS_SOLVE::vcs_popPhaseID() {
int iphasePop = -1;
int iph;
int irxn, kspec;
doublereal FephaseMax = -1.0E30;
doublereal Fephase = -1.0E30;
vcs_VolPhase *Vphase = 0;
int VCS_SOLVE::vcs_phaseStabilityTest(const int iph) {
#ifdef DEBUG_MODE
char anote[128];
if (m_debug_print_lvl >= 2) {
plogf(" --- vcs_popPhaseID() called\n");
plogf(" --- Phase Status F_e MoleNum\n");
plogf(" --------------------------------------------------------------\n");
}
#endif
for (iph = 0; iph < m_numPhases; iph++) {
Vphase = m_VolPhaseList[iph];
int existence = Vphase->exists();
strcpy(anote, "");
if (existence > 0) {
#ifdef DEBUG_MODE
if (m_debug_print_lvl >= 2) {
plogf(" --- %18s %5d NA %11.3e\n",
Vphase->PhaseName.c_str(),
existence,
m_tPhaseMoles_old[iph]);
}
#endif
} else {
if (Vphase->m_singleSpecies) {
/***********************************************************************
*
* Single Phase Stability Resolution
*
***********************************************************************/
kspec = Vphase->spGlobalIndexVCS(0);
irxn = kspec - m_numComponents;
doublereal deltaGRxn = m_deltaGRxn_old[irxn];
Fephase = exp(-deltaGRxn) - 1.0;
if (Fephase > 0.0) {
#ifdef DEBUG_MODE
strcpy(anote," (ready to be birthed)");
#endif
if (Fephase > FephaseMax) {
iphasePop = iph;
FephaseMax = Fephase;
#ifdef DEBUG_MODE
strcpy(anote," (chosen to be birthed)");
#endif
}
}
#ifdef DEBUG_MODE
if (m_debug_print_lvl >= 2) {
plogf(" --- %18s %5d NA %11.3g %s\n",
Vphase->PhaseName.c_str(),
existence, Fephase,
m_tPhaseMoles_old[iph], anote);
}
#endif
} else {
/***********************************************************************
*
* MultiSpecies Phase Stability Resolution
*
***********************************************************************/
if (vcs_popPhasePossible(iph)) {
Fephase = vcs_phaseStabilityTest(iph);
if (Fephase > 0.0) {
if (Fephase > FephaseMax) {
iphasePop = iph;
FephaseMax = Fephase;
}
} else {
if (Fephase > FephaseMax) {
FephaseMax = Fephase;
}
}
#ifdef DEBUG_MODE
if (m_debug_print_lvl >= 2) {
plogf(" --- %18s %5d %11.3g %11.3g\n",
Vphase->PhaseName.c_str(),
existence, Fephase,
m_tPhaseMoles_old[iph]);
}
#endif
} else {
#ifdef DEBUG_MODE
if (m_debug_print_lvl >= 2) {
plogf(" --- %18s %5d blocked %11.3g\n",
Vphase->PhaseName.c_str(),
existence, m_tPhaseMoles_old[iph]);
}
#endif
}
}
}
}
#ifdef DEBUG_MODE
if (m_debug_print_lvl >= 2) {
plogf(" --------------------------------------------------------------\n");
}
#endif
return iphasePop;
}
// Calculates the deltas of the reactions due to phases popping
// into existence
/*
* @param iphasePop Phase id of the phase that will come into existence
*
* Output
* -------
* m_deltaMolNumSpecies(irxn) : reaction adjustments, where irxn refers
* to the irxn'th species
* formation reaction. This adjustment
* is for species
* irxn + M, where M is the number
* of components.
*
* @return Returns an int representing the status of the step
* - 0 : normal return
* - 1 : A single species phase species has been zeroed out
* in this routine. The species is a noncomponent
* - 2 : Same as one but, the zeroed species is a component.
* - 3 : Nothing was done because the phase couldn't be birthed
* because a needed component is zero.
*/
int VCS_SOLVE::vcs_popPhaseRxnStepSizes(const int iphasePop) {
vcs_VolPhase *Vphase = m_VolPhaseList[iphasePop];
// Identify the first species in the phase
int kspec = Vphase->spGlobalIndexVCS(0);
// Identify the formation reaction for that species
int irxn = kspec - m_numComponents;
doublereal s;
int j, k;
// Calculate the initial moles of the phase being born.
// Here we set it to 10x of the value which would cause the phase to be
// zeroed out within the algorithm. We may later adjust the value.
doublereal tPhaseMoles = 10. * m_totalMolNum * VCS_DELETE_PHASE_CUTOFF;
#ifdef DEBUG_MODE
int existence = Vphase->exists();
if (existence > 0) {
printf("ERROR vcs_popPhaseRxnStepSizes called for a phase that exists!");
exit(-1);
}
char anote[256];
if (m_debug_print_lvl >= 2) {
plogf(" --- vcs_popPhaseRxnStepSizes() called to pop phase %s %d into existence\n",
Vphase->PhaseName.c_str(), iphasePop);
}
#endif
// Section for a single-species phase
//
if (Vphase->m_singleSpecies) {
s = 0.0;
double *dnPhase_irxn = m_deltaMolNumPhase[irxn];
for (j = 0; j < m_numComponents; ++j) {
if (!m_SSPhase[j]) {
if (m_molNumSpecies_old[j] > 0.0) {
s += SQUARE(m_stoichCoeffRxnMatrix[irxn][j]) / m_molNumSpecies_old[j];
}
}
}
for (j = 0; j < m_numPhases; j++) {
Vphase = m_VolPhaseList[j];
if (! Vphase->m_singleSpecies) {
if (m_tPhaseMoles_old[j] > 0.0)
s -= SQUARE(dnPhase_irxn[j]) / m_tPhaseMoles_old[j];
}
}
if (s != 0.0) {
double s_old = s;
s = vcs_Hessian_diag_adj(irxn, s_old);
#ifdef DEBUG_MODE
if (s_old != s) {
sprintf(anote, "Normal calc: diag adjusted from %g "
"to %g due to act coeff", s_old, s);
}
#endif
m_deltaMolNumSpecies[kspec] = -m_deltaGRxn_new[irxn] / s;
} else {
// Ok, s is equal to zero. We can not apply a sophisticated theory
// to birth the phase. Just pick a small delta and go with it.
m_deltaMolNumSpecies[kspec] = tPhaseMoles;
}
/*
* section to do damping of the m_deltaMolNumSpecies[]
*/
for (j = 0; j < m_numComponents; ++j) {
double stoicC = m_stoichCoeffRxnMatrix[irxn][j];
if (stoicC != 0.0) {
if (m_elType[j] == VCS_ELEM_TYPE_ABSPOS) {
double negChangeComp = - stoicC * m_deltaMolNumSpecies[kspec];
if (negChangeComp > m_molNumSpecies_old[j]) {
if (m_molNumSpecies_old[j] > 0.0) {
#ifdef DEBUG_MODE
sprintf(anote, "Delta damped from %g "
"to %g due to component %d (%10s) going neg", m_deltaMolNumSpecies[kspec],
-m_molNumSpecies_old[j]/stoicC, j, m_speciesName[j].c_str());
#endif
m_deltaMolNumSpecies[kspec] = - 0.5 * m_molNumSpecies_old[j] / stoicC;
} else {
#ifdef DEBUG_MODE
sprintf(anote, "Delta damped from %g "
"to %g due to component %d (%10s) zero", m_deltaMolNumSpecies[kspec],
-m_molNumSpecies_old[j]/stoicC, j, m_speciesName[j].c_str());
#endif
m_deltaMolNumSpecies[kspec] = 0.0;
}
}
}
}
}
// Implement a damping term that limits m_deltaMolNumSpecies to the size of the mole number
if (-m_deltaMolNumSpecies[kspec] > m_molNumSpecies_old[kspec]) {
#ifdef DEBUG_MODE
sprintf(anote, "Delta damped from %g "
"to %g due to %s going negative", m_deltaMolNumSpecies[kspec],
-m_molNumSpecies_old[kspec], m_speciesName[kspec].c_str());
#endif
m_deltaMolNumSpecies[kspec] = -m_molNumSpecies_old[kspec];
}
} else {
vector<doublereal> fracDelta(Vphase->nSpecies());
vector<doublereal> X_est(Vphase->nSpecies());
fracDelta = Vphase->fractionCreationDeltas();
double sumFrac = 0.0;
for (k = 0; k < Vphase->nSpecies(); k++) {
sumFrac += fracDelta[k];
}
for (k = 0; k < Vphase->nSpecies(); k++) {
X_est[k] = fracDelta[k] / sumFrac;
}
doublereal deltaMolNumPhase = tPhaseMoles;
doublereal damp = 1.0;
m_deltaGRxn_tmp = m_molNumSpecies_old;
double * molNumSpecies_tmp = DATA_PTR(m_deltaGRxn_tmp);
for (k = 0; k < Vphase->nSpecies(); k++) {
kspec = Vphase->spGlobalIndexVCS(k);
double delmol = deltaMolNumPhase * X_est[k];
irxn = kspec - m_numComponents;
if (kspec >= m_numComponents) {
for (j = 0; j < m_numComponents; ++j) {
double stoicC = m_stoichCoeffRxnMatrix[irxn][j];
if (stoicC != 0.0) {
if (m_elType[j] == VCS_ELEM_TYPE_ABSPOS) {
molNumSpecies_tmp[j] += stoicC * delmol;
}
}
}
}
}
doublereal ratioComp = 0.0;
for (j = 0; j < m_numComponents; ++j) {
double deltaJ = m_molNumSpecies_old[j] - molNumSpecies_tmp[j];
if (molNumSpecies_tmp[j] < 0.0) {
ratioComp = 1.0;
if (deltaJ > 0.0) {
double delta0 = m_molNumSpecies_old[j];
double dampj = delta0 / deltaJ * 0.9;
if (dampj < damp) {
damp = dampj;
}
}
} else {
if (m_elType[j] == VCS_ELEM_TYPE_ABSPOS) {
int jph = m_phaseID[j];
if ((jph != iphasePop) && (!m_SSPhase[j])) {
double fdeltaJ = fabs(deltaJ);
if ( m_molNumSpecies_old[j] > 0.0) {
ratioComp = MAX(ratioComp, fdeltaJ/ m_molNumSpecies_old[j]);
}
}
}
}
}
// We may have greatly underestimated the deltaMoles for the phase pop
// Here we create a damp > 1 to account for this possibility.
// We adjust upwards to make sure that a component in an existing multispecies
// phase is modified by a factor of 1/1000.
if (ratioComp > 1.0E-30) {
if (ratioComp < 0.001) {
damp = 0.001 / ratioComp;
}
}
if (damp <= 1.0E-6) {
return 3;
}
for (k = 0; k < Vphase->nSpecies(); k++) {
kspec = Vphase->spGlobalIndexVCS(k);
if (kspec < m_numComponents) {
m_speciesStatus[kspec] = VCS_SPECIES_COMPONENT;
} else {
m_deltaMolNumSpecies[kspec] = deltaMolNumPhase * X_est[k] * damp;
if (X_est[k] > 1.0E-3) {
m_speciesStatus[kspec] = VCS_SPECIES_MAJOR;
} else {
m_speciesStatus[kspec] = VCS_SPECIES_MINOR;
}
}
}
}
return 0;
}
//
double VCS_SOLVE::vcs_phaseStabilityTest(const int iph) {
/*
* We will use the _new state calc here
*/
int kspec, irxn, k;
int kspec, irxn, k, i, kc, kc_spec;
vcs_VolPhase *Vphase = m_VolPhaseList[iph];
double deltaGRxn;
doublereal deltaGRxn;
// We will do a full newton calculation later, but for now, ...
bool doSuccessiveSubstitution = true;
int res = 0;
double funcPhaseStability;
vector<doublereal> X_est(Vphase->nSpecies(), 0.0);
vector<doublereal> delFrac(Vphase->nSpecies(), 0.0);
vector<doublereal> E_phi(Vphase->nSpecies(), 0.0);
vector<doublereal> fracDelta_new(Vphase->nSpecies(), 0.0);
vector<doublereal> fracDelta_old(Vphase->nSpecies(), 0.0);
vector<doublereal> fracDelta_raw(Vphase->nSpecies(), 0.0);
vector<double> X_est(Vphase->nSpecies(), 0.0);
vector<double> X_est_old(Vphase->nSpecies(), 0.0);
vector<double> delX(Vphase->nSpecies(), 0.0);
vector<double> E_phi(Vphase->nSpecies(), 0.0);
double damp = 1.0;
double normUpdate = 1.0;
double normUpdateOld = 1.0;
vector<doublereal> m_feSpecies_Deficient(m_numComponents, 0.0);
doublereal damp = 1.0;
doublereal dampOld = 1.0;
doublereal normUpdate = 1.0;
doublereal normUpdateOld = 1.0;
doublereal sum = 0.0;
doublereal dirProd = 0.0;
doublereal dirProdOld = 0.0;
// get the activity coefficients
Vphase->sendToVCS_ActCoeff(VCS_STATECALC_OLD, VCS_DATA_PTR(m_actCoeffSpecies_new));
// Get the storred estimate for the composition of the phase if
// it gets created
fracDelta_new = Vphase->fractionCreationDeltas();
#ifdef DEBUG_MODE
if (m_temperature < 380.) {
// fracDelta_new[0] = 0.8;
// fracDelta_new[1] = 0.1;
// fracDelta_new[2] = 1.0E-8;
// fracDelta_new[3] = 0.1;
//fracDelta_new[4] = 1.0E-8;
}
if (m_temperature < 390.) {
printf("we are here\n");
}
#endif
bool oneIsComponent = false;
std::vector<int> componentList;
for (k = 0; k < Vphase->nSpecies(); k++) {
kspec = Vphase->spGlobalIndexVCS(k);
if (kspec < m_numComponents) {
oneIsComponent = true;
componentList.push_back(k);
}
}
for (k = 0; k < m_numComponents; k++) {
m_feSpecies_Deficient[k] = m_feSpecies_old[k];
}
normUpdate = 0.1 * vcs_l2norm(fracDelta_new);
damp = 1.0E-2;
if (doSuccessiveSubstitution) {
for (int its = 0; its < 20; its++) {
bool converged = false;
for (int its = 0; its < 200 && (!converged); its++) {
dampOld = damp;
normUpdateOld = normUpdate;
for (k = 0; k < Vphase->nSpecies(); k++) {
X_est_old[k] = X_est[k];
fracDelta_old = fracDelta_new;
dirProdOld = dirProd;
// Given a set of fracDelta's, we calculate the fracDelta's
// for the component species, if any
for (i = 0; i < (int) componentList.size(); i++) {
kc = componentList[i];
kc_spec = Vphase->spGlobalIndexVCS(kc);
fracDelta_old[kc] = 0.0;
for (k = 0; k < Vphase->nSpecies(); k++) {
kspec = Vphase->spGlobalIndexVCS(k);
irxn = kspec - m_numComponents;
if (irxn >= 0) {
fracDelta_old[kc] += m_stoichCoeffRxnMatrix[irxn][kc_spec] * fracDelta_old[k];
}
}
}
double poly = -1.0;
// Now, calculate the predicted mole fractions, X_est[k]
double sumFrac = 0.0;
for (k = 0; k < Vphase->nSpecies(); k++) {
kspec = Vphase->spGlobalIndexVCS(k);
irxn = kspec - m_numComponents;
deltaGRxn = m_deltaGRxn_old[irxn];
// We may need to look at deltaGRxn for components!
if (irxn >= 0) {
if (deltaGRxn > 50.0) deltaGRxn = 50.0;
if (deltaGRxn < -50.0) deltaGRxn = -50.0;
E_phi[k] = exp(-deltaGRxn)/m_actCoeffSpecies_new[kspec];
poly += E_phi[k];
sumFrac += fracDelta_old[k];
}
double sum_Xcomp = 0.0;
for (k = 0; k < Vphase->nSpecies(); k++) {
X_est[k] = fracDelta_old[k] / sumFrac;
kc_spec = Vphase->spGlobalIndexVCS(k);
if (kc_spec < m_numComponents) {
sum_Xcomp += X_est[k];
}
}
double sum = poly + 1.0;
for (k = 0; k < Vphase->nSpecies(); k++) {
delX[k] = E_phi[k]/sum - X_est_old[k];
}
normUpdate = vcs_l2norm(delX);
// Figure out the damping coefficient
double ratio = normUpdate / normUpdateOld;
if (ratio < 0.4) {
damp = 1.0;
} else if (ratio > 1.0) {
damp = 0.03;
} else {
damp = 0.1;
}
/*
* Feed the newly formed estimate of the mole fractions back into the
* ThermoPhase object
*/
Vphase->setMoleFractionsState(0.0, VCS_DATA_PTR(X_est), VCS_STATECALC_PHASESTABILITY);
/*
* get the activity coefficients
*/
Vphase->sendToVCS_ActCoeff(VCS_STATECALC_OLD, VCS_DATA_PTR(m_actCoeffSpecies_new));
/*
* first Calculate altered chemical potentials for component species
* belonging to this phase.
*/
for (i = 0; i < (int) componentList.size(); i++) {
kc = componentList[i];
kc_spec = Vphase->spGlobalIndexVCS(kc);
if ( X_est[kc] > VCS_DELETE_MINORSPECIES_CUTOFF) {
m_feSpecies_Deficient[kc_spec] = m_feSpecies_old[kc_spec]
+ log(m_actCoeffSpecies_new[kc_spec] * X_est[kc]);
} else {
m_feSpecies_Deficient[kc_spec] = m_feSpecies_old[kc_spec]
+ log(m_actCoeffSpecies_new[kc_spec] * VCS_DELETE_MINORSPECIES_CUTOFF);
}
}
for (i = 0; i < (int) componentList.size(); i++) {
kc = componentList[i];
kc_spec = Vphase->spGlobalIndexVCS(kc);
for (k = 0; k < Vphase->nSpecies(); k++) {
kspec = Vphase->spGlobalIndexVCS(k);
irxn = kspec - m_numComponents;
if (irxn >= 0) {
if (i == 0) {
m_deltaGRxn_Deficient[irxn] = m_deltaGRxn_old[irxn];
}
double *dtmp_ptr = m_stoichCoeffRxnMatrix[irxn];
if (dtmp_ptr[kc_spec] != 0.0) {
m_deltaGRxn_Deficient[irxn] +=
dtmp_ptr[kc_spec] * (m_feSpecies_Deficient[kc_spec]- m_feSpecies_old[kc_spec]);
}
}
}
}
/*
* Calculate the E_phi's
*/
sum = 0.0;
funcPhaseStability = sum_Xcomp - 1.0;
for (k = 0; k < Vphase->nSpecies(); k++) {
X_est[k] = X_est_old[k] + damp * delX[k];
kspec = Vphase->spGlobalIndexVCS(k);
irxn = kspec - m_numComponents;
if (irxn >= 0) {
deltaGRxn = m_deltaGRxn_Deficient[irxn];
if (deltaGRxn > 50.0) deltaGRxn = 50.0;
if (deltaGRxn < -50.0) deltaGRxn = -50.0;
E_phi[k] = std::exp(-deltaGRxn) / m_actCoeffSpecies_new[kspec];
sum += E_phi[k];
funcPhaseStability += E_phi[k];
} else {
E_phi[k] = 0.0;
}
}
/*
* Calculate the raw estimate of the new fracs
*/
for (k = 0; k < Vphase->nSpecies(); k++) {
kspec = Vphase->spGlobalIndexVCS(k);
irxn = kspec - m_numComponents;
double b = E_phi[k] / sum * (1.0 - sum_Xcomp);
if (irxn >= 0) {
fracDelta_raw[k] = (sumFrac - fracDelta_old[k]) * b / (1.0 - b);
}
}
// Given a set of fracDelta's, we calculate the fracDelta's
// for the component species, if any
for (i = 0; i < (int) componentList.size(); i++) {
kc = componentList[i];
kc_spec = Vphase->spGlobalIndexVCS(kc);
fracDelta_raw[kc] = 0.0;
for (k = 0; k < Vphase->nSpecies(); k++) {
kspec = Vphase->spGlobalIndexVCS(k);
irxn = kspec - m_numComponents;
if (irxn >= 0) {
fracDelta_raw[kc] += m_stoichCoeffRxnMatrix[irxn][kc_spec] * fracDelta_raw[k];
}
}
}
/*
* Now possibly dampen the estimate.
*/
doublereal sumADel = 0.0;
for (k = 0; k < Vphase->nSpecies(); k++) {
delFrac[k] = fracDelta_raw[k] - fracDelta_old[k];
sumADel += fabs(delFrac[k]);
}
normUpdate = vcs_l2norm(delFrac);
dirProd = 0.0;
for (k = 0; k < Vphase->nSpecies(); k++) {
dirProd += fracDelta_old[k] * delFrac[k];
}
bool crossedSign = false;
if (dirProd * dirProdOld < 0.0) {
crossedSign = true;
}
damp = 0.5;
if (dampOld < 0.25) {
damp = 2.0 * dampOld;
}
if (crossedSign) {
if (normUpdate *1.5 > normUpdateOld) {
damp = 0.5 * dampOld;
} else if (normUpdate *2.0 > normUpdateOld) {
damp = 0.8 * dampOld;
}
} else {
if (normUpdate > normUpdateOld * 2.0) {
damp = 0.6 * dampOld;
} else if (normUpdate > normUpdateOld * 1.2) {
damp = 0.9 * dampOld;
}
}
for (k = 0; k < Vphase->nSpecies(); k++) {
kspec = Vphase->spGlobalIndexVCS(k);
m_molNumSpecies_new[kspec] = X_est[k];
if (fabs(damp * delFrac[k]) > 0.3*fabs(fracDelta_old[k])) {
damp = MAX(0.3*fabs(fracDelta_old[k]) / fabs( delFrac[k]), 1.0E-8/fabs( delFrac[k]));
}
if (delFrac[k] < 0.0) {
if (2.0 * damp * (-delFrac[k]) > fracDelta_old[k]) {
damp = fracDelta_old[k] / (2.0 * (-delFrac[k]));
}
}
if (delFrac[k] > 0.0) {
if (2.0 * damp * delFrac[k] > fracDelta_old[k]) {
damp = fracDelta_old[k] / (2.0 * delFrac[k]);
}
}
}
if (damp < 0.000001) {
damp = 0.000001;
}
for (k = 0; k < Vphase->nSpecies(); k++) {
fracDelta_new[k] = fracDelta_old[k] + damp * (delFrac[k]);
}
if (normUpdate < 1.0E-5) {
converged = true;
}
Vphase->setMolesFromVCS(VCS_STATECALC_NEW);
}
if (converged) {
Vphase->setMoleFractionsState(0.0, VCS_DATA_PTR(X_est), VCS_STATECALC_PHASESTABILITY);
Vphase->setFractionCreationDeltas( VCS_DATA_PTR(fracDelta_new));
}
} else {
printf("not done yet\n");
exit(-1);
}
return res;
return funcPhaseStability;
}
}

View file

@ -27,10 +27,12 @@ namespace VCSnonideal {
*
* Output
* -------
* m_deltaMolNumSpecies(irxn) : reaction adjustments, where irxn refers
* m_deltaMolNumSpecies[kspec] : reaction adjustments, where irxn refers
* to the irxn'th species
* formation reaction. This adjustment is for species
* irxn + M, where M is the number of components.
* formation reaction. This adjustment
* is for species
* irxn + M, where M is the number
* of components.
*
* Special branching occurs sometimes. This causes the component basis
* to be reevaluated
@ -127,7 +129,7 @@ namespace VCSnonideal {
}
} else {
/********************************************************************/
/************************* REGULAR PROCESSING ************/
/************************* REGULAR PROCESSING ***********************/
/********************************************************************/
/*
* First take care of cases where we want to bail out

View file

@ -498,7 +498,37 @@ public:
*
*/
void vcs_updateVP(const int stateCalc);
//! Utility function that evaluates whether a phase can be popped
//! into existence
/*!
* @param iphasePop id of the phase, which is currently zeroed,
*
* @return Returns true if the phase can come into existence
* and false otherwise.
*/
bool vcs_popPhasePossible(const int iphasePop) const;
//! Decision as to whether a phase pops back into existence
/*!
* @return returns the phase id of the phase that pops back into
* existence. Returns -1 if there are no phases
*/
int vcs_popPhaseID();
//! Calculates the deltas of the reactions due to phases popping
//! into existence
/*!
* @param iphasePop Phase id of the phase that will come into existence
*
* @return Returns an int representing the status of the step
* - 0 : normal return
* - 1 : A single species phase species has been zeroed out
* in this routine. The species is a noncomponent
* - 2 : Same as one but, the zeroed species is a component.
*/
int vcs_popPhaseRxnStepSizes(const int iphasePop);
//! Calculates formation reaction step sizes.
/*!
@ -633,8 +663,13 @@ public:
double vcs_birthGuess(const int kspec);
int vcs_phaseStabilityTest(const int iph);
//! Main program to test whether a deleted phase should be brought
//! back into existence
/*!
*
* @param iph Phase id of the deleted phase
*/
double vcs_phaseStabilityTest(const int iph);
//! Solve an equilibrium problem at a particular fixed temperature
//! and pressure
@ -1441,7 +1476,7 @@ public:
* stoichiometric coefficient of one is assumed for the
* species K in this mechanism.
*
* NOTE: K = IRXN + NC
* NOTE: kspec = Irxn + m_numComponents
*
* sc[irxn][j] :
* j refers to the component number, and irxn

View file

@ -447,45 +447,74 @@ namespace VCSnonideal {
vcs_dzero(VCS_DATA_PTR(m_deltaMolNumSpecies), m_numSpeciesTot);
/*
* Figure out whether we will calculate new reaction step sizes
* for the major species.
* -> We won't if all species are minors (im), OR
* all major species have already converged
* First step is a major branch in the algorithm.
* We first determine if a phase pops into existence.
*/
if (!(MajorSpeciesHaveConverged) && ! allMinorZeroedSpecies) {
soldel = vcs_RxnStepSizes();
/* - If SOLDEL is true then we encountered a reaction between */
/* - single-species-phase species, only, and have adjusted */
/* - the mole number vector, W(), directly. In this case, */
/* - we should immediately go back and recompute a new */
/* - component basis, if the species that was zeroed was */
/* - a component. SOLDEL is true when this is so. */
if (soldel > 0) {
/* - We have changed the base mole number amongst single- */
/* - species-phase species. However, we don't need to */
/* - recaculate their chemical potentials because they */
/* - are constant, anyway! */
if (soldel == 2) {
goto L_COMPONENT_CALC;
}
/* - We have not changed the actual DG values for */
/* - any species, even the one we deleted. Thus, */
/* - we don't need to start over. */
}
} else {
int iphasePop = vcs_popPhaseID();
/*
*
*/
soldel = -1;
if (iphasePop >= 0) {
soldel = vcs_popPhaseRxnStepSizes(iphasePop);
if (soldel == 3) {
iphasePop = -1;
#ifdef DEBUG_MODE
if (m_debug_print_lvl >= 2) {
if (allMinorZeroedSpecies) {
plogf(" --- vcs_RxnStepSizes not called because all"
"species are minors\n");
} else {
plogf(" --- vcs_RxnStepSizes not called because "
"all majors have converged\n");
if (m_debug_print_lvl >= 2) {
plogf(" --- vcs_popPhaseRxnStepSizes() was called but stoich prevented phase %d popping\n");
}
}
#endif
}
}
if (iphasePop < 0) {
/*
* Figure out whether we will calculate new reaction step sizes
* for the major species.
* -> We won't if all species are minors (im), OR
* all major species have already converged
*/
if (!(MajorSpeciesHaveConverged) && ! allMinorZeroedSpecies) {
soldel = vcs_RxnStepSizes();
/* - If SOLDEL is true then we encountered a reaction between */
/* - single-species-phase species, only, and have adjusted */
/* - the mole number vector, W(), directly. In this case, */
/* - we should immediately go back and recompute a new */
/* - component basis, if the species that was zeroed was */
/* - a component. SOLDEL is true when this is so. */
if (soldel > 0) {
/* - We have changed the base mole number amongst single- */
/* - species-phase species. However, we don't need to */
/* - recaculate their chemical potentials because they */
/* - are constant, anyway! */
if (soldel == 2) {
goto L_COMPONENT_CALC;
}
/* - We have not changed the actual DG values for */
/* - any species, even the one we deleted. Thus, */
/* - we don't need to start over. */
}
} else {
#ifdef DEBUG_MODE
if (m_debug_print_lvl >= 2) {
if (allMinorZeroedSpecies) {
plogf(" --- vcs_RxnStepSizes not called because all"
"species are minors\n");
} else {
plogf(" --- vcs_RxnStepSizes not called because "
"all majors have converged\n");
}
}
#endif
}
}
#ifdef DEBUG_MODE
else {
if (m_debug_print_lvl >= 2) {
plogf(" --- vcs_RxnStepSizes not called because alternative"
"phase creation delta was used instead\n");
}
}
#endif
lec = FALSE;
doPhaseDeleteIph = -1;
doPhaseDeleteKspec = -1;
@ -544,389 +573,403 @@ namespace VCSnonideal {
#ifdef DEBUG_MODE
ANOTE[0] = '\0';
#endif
if (m_speciesStatus[kspec] == VCS_SPECIES_INTERFACIALVOLTAGE) {
/********************************************************************/
/************************ VOLTAGE SPECIES ***************************/
/********************************************************************/
#ifdef DEBUG_MODE
dx = vcs_minor_alt_calc(kspec, irxn, &soldel, ANOTE);
#else
dx = vcs_minor_alt_calc(kspec, irxn, &soldel);
#endif
m_deltaMolNumSpecies[kspec] = dx;
}
else if (m_speciesStatus[kspec] < VCS_SPECIES_MINOR) {
/********************************************************************/
/********************** ZEROED OUT SPECIES **************************/
/********************************************************************/
bool resurrect = true;
#ifdef DEBUG_MODE
if (m_debug_print_lvl >= 3) {
plogf(" --- %s currently zeroed (SpStatus=%-2d):",
m_speciesName[kspec].c_str(), m_speciesStatus[kspec]);
plogf("%3d DG = %11.4E WT = %11.4E W = %11.4E DS = %11.4E\n",
irxn, m_deltaGRxn_new[irxn], m_molNumSpecies_new[kspec],
m_molNumSpecies_old[kspec], m_deltaMolNumSpecies[kspec]);
}
#endif
// HKM Alternative is to not allow ds[] = 0.0 phases
// to pop back into existence. For esthetics, I'm allowing this.
// so that dg < 0.0 phases with zero mole numbers become components.
// This is also better, because that component will be the first
// one to pop into existence if there is a minute quantity of the element.
// This could change in the future.
//if (dg[irxn] >= 0.0 || ds[kspec] <= 0.0) {
if (m_deltaGRxn_new[irxn] >= 0.0 ) {
m_molNumSpecies_new[kspec] = m_molNumSpecies_old[kspec];
m_deltaMolNumSpecies[kspec] = 0.0;
resurrect = false;
#ifdef DEBUG_MODE
sprintf(ANOTE, "Species stays zeroed: DG = %11.4E",
m_deltaGRxn_new[irxn]);
if (m_deltaGRxn_new[irxn] < 0.0) {
sprintf(ANOTE, "Species stays zeroed even though dg neg:DG = %11.4E, ds zeroed ",
m_deltaGRxn_new[irxn]);
}
#endif
if (iphasePop >= 0) {
if (iph == iphasePop) {
dx = m_deltaMolNumSpecies[kspec];
m_molNumSpecies_new[kspec] = m_molNumSpecies_old[kspec] + m_deltaMolNumSpecies[kspec];
#ifdef DEBUG_MODE
sprintf(ANOTE, "Phase pop");
#endif
} else {
for (int j = 0; j < m_numElemConstraints; ++j) {
int elType = m_elType[j];
if (elType == VCS_ELEM_TYPE_ABSPOS) {
double atomComp = m_formulaMatrix[j][kspec];
if (atomComp > 0.0) {
double maxPermissible = m_elemAbundancesGoal[j] / atomComp;
if (maxPermissible < VCS_DELETE_MINORSPECIES_CUTOFF) {
#ifdef DEBUG_MODE
sprintf(ANOTE, "Species stays zeroed even though dG "
"neg, because of %s elemAbund",
m_elementName[j].c_str());
#endif
resurrect = false;
break;
}
}
}
}
}
/*
* Resurrect the species
*/
if (resurrect) {
bool phaseResurrected = false;
if (Vphase->exists() == VCS_PHASE_EXIST_NO) {
//Vphase->setExistence(1);
phaseResurrected = true;
}
--m_numRxnMinorZeroed;
if (phaseResurrected) {
#ifdef DEBUG_MODE
if (m_debug_print_lvl >= 2) {
plogf(" --- Zeroed species changed to major: ");
plogf("%-12s\n", m_speciesName[kspec].c_str());
}
#endif
m_speciesStatus[kspec] = VCS_SPECIES_MAJOR;
MajorSpeciesHaveConverged = false;
allMinorZeroedSpecies = false;
} else {
#ifdef DEBUG_MODE
if (m_debug_print_lvl >= 2) {
plogf(" --- Zeroed species changed to minor: ");
plogf("%-12s\n", m_speciesName[kspec].c_str());
}
#endif
m_speciesStatus[kspec] = VCS_SPECIES_MINOR;
}
if (m_deltaMolNumSpecies[kspec] > 0.0) {
dx = m_deltaMolNumSpecies[kspec] * 0.01;
m_molNumSpecies_new[kspec] = m_molNumSpecies_old[kspec] + dx;
} else {
m_molNumSpecies_new[kspec] = m_totalMolNum * VCS_DELETE_PHASE_CUTOFF * 10.;
dx = m_molNumSpecies_new[kspec] - m_molNumSpecies_old[kspec];
}
m_deltaMolNumSpecies[kspec] = dx;
#ifdef DEBUG_MODE
sprintf(ANOTE, "Born:IC=-1 to IC=1:DG=%11.4E", m_deltaGRxn_new[irxn]);
#endif
} else {
m_molNumSpecies_new[kspec] = m_molNumSpecies_old[kspec];
m_deltaMolNumSpecies[kspec] = 0.0;
dx = 0.0;
}
} else if (m_speciesStatus[kspec] == VCS_SPECIES_MINOR) {
/********************************************************************/
/***************************** MINOR SPECIES ************************/
/********************************************************************/
/*
* Unless ITI isn't equal to zero we zero out changes
* to minor species.
*/
if (iti != 0) {
m_molNumSpecies_new[kspec] = m_molNumSpecies_old[kspec];
m_deltaMolNumSpecies[kspec] = 0.0;
dx = 0.0;
#ifdef DEBUG_MODE
sprintf(ANOTE,"minor species not considered");
if (m_debug_print_lvl >= 2) {
plogf(" --- "); plogf("%-12s", m_speciesName[kspec].c_str());
plogf("%3d%11.4E%11.4E%11.4E | %s",
m_speciesStatus[kspec], m_molNumSpecies_old[kspec], m_molNumSpecies_new[kspec],
m_deltaMolNumSpecies[kspec], ANOTE);
plogendl();
}
#endif
continue;
}
/*
* Minor species alternative calculation
* ---------------------------------------
* This is based upon the following approximation:
* The mole fraction changes due to these reactions don't affect
* the mole numbers of the component species. Therefore the
* following approximation is valid for an ideal solution
* 0 = DG(I) + log(WT(I)/W(I))
* (DG contains the contribution from FF(I) + log(W(I)/TL) )
* Thus,
* WT(I) = W(I) EXP(-DG(I))
* If soldel is true on return, then we branch to the section
* that deletes a species from the current set of active species.
*/
#ifdef DEBUG_MODE
dx = vcs_minor_alt_calc(kspec, irxn, &soldel, ANOTE);
#else
dx = vcs_minor_alt_calc(kspec, irxn, &soldel);
#endif
m_deltaMolNumSpecies[kspec] = dx;
m_molNumSpecies_new[kspec] = m_molNumSpecies_old[kspec] + dx;
if (soldel) {
/*******************************************************************/
/***** DELETE MINOR SPECIES LESS THAN VCS_DELETE_SPECIES_CUTOFF */
/***** MOLE NUMBER */
/*******************************************************************/
#ifdef DEBUG_MODE
if (m_debug_print_lvl >= 2) {
plogf(" --- Delete minor species in multispec phase: %-12s",
m_speciesName[kspec].c_str());
plogendl();
}
#endif
m_deltaMolNumSpecies[kspec] = 0.0;
/*
* Delete species, kspec. The alternate return is for the case
* where all species become deleted. Then, we need to
* branch to the code where we reevaluate the deletion
* of all species.
*/
lnospec = vcs_delete_species(kspec);
if (lnospec) goto L_RECHECK_DELETED;
/*
* Go back to consider the next species in the list.
* Note, however, that the next species in the list is now
* in slot l. In deleting the previous species L, We have
* exchanged slot MR with slot l, and then have
* decremented MR.
* Therefore, we will decrement the species counter, here.
*/
--irxn;
#ifdef DEBUG_MODE
goto L_MAIN_LOOP_END_NO_PRINT;
#else
goto L_MAIN_LOOP_END;
#endif
}
} else {
/********************************************************************/
/*********************** MAJOR SPECIES ******************************/
/********************************************************************/
#ifdef DEBUG_MODE
sprintf(ANOTE, "Normal Major Calc");
if (m_speciesStatus[kspec] == VCS_SPECIES_INTERFACIALVOLTAGE) {
/********************************************************************/
/************************ VOLTAGE SPECIES ***************************/
/********************************************************************/
#ifdef DEBUG_MODE
dx = vcs_minor_alt_calc(kspec, irxn, &soldel, ANOTE);
#else
dx = vcs_minor_alt_calc(kspec, irxn, &soldel);
#endif
/*
* Check for superconvergence of the formation reaction. Do
* nothing if it is superconverged. Skip to the end of the
* irxn loop if it is superconverged.
*/
if (fabs(m_deltaGRxn_new[irxn]) <= m_tolmaj2) {
m_molNumSpecies_new[kspec] = m_molNumSpecies_old[kspec];
m_deltaMolNumSpecies[kspec] = 0.0;
dx = 0.0;
m_deltaMolNumSpecies[kspec] = dx;
}
else if (m_speciesStatus[kspec] < VCS_SPECIES_MINOR) {
/********************************************************************/
/********************** ZEROED OUT SPECIES **************************/
/********************************************************************/
bool resurrect = true;
#ifdef DEBUG_MODE
sprintf(ANOTE, "major species is converged");
if (m_debug_print_lvl >= 2) {
plogf(" --- "); plogf("%-12s", m_speciesName[kspec].c_str());
plogf("%3d%11.4E%11.4E%11.4E | %s",
m_speciesStatus[kspec], m_molNumSpecies_old[kspec], m_molNumSpecies_new[kspec],
m_deltaMolNumSpecies[kspec], ANOTE);
plogendl();
if (m_debug_print_lvl >= 3) {
plogf(" --- %s currently zeroed (SpStatus=%-2d):",
m_speciesName[kspec].c_str(), m_speciesStatus[kspec]);
plogf("%3d DG = %11.4E WT = %11.4E W = %11.4E DS = %11.4E\n",
irxn, m_deltaGRxn_new[irxn], m_molNumSpecies_new[kspec],
m_molNumSpecies_old[kspec], m_deltaMolNumSpecies[kspec]);
}
#endif
continue;
}
/*
* Set the initial step size, dx, equal to the value produced
* by the routine, vcs_RxnStepSize().
*
* Note the multiplition logic is to make sure that
* dg[] didn't change sign due to w[] changing in the
* middle of the iteration. (it can if a single species
* phase goes out of existence).
*/
if ((m_deltaGRxn_new[irxn] * m_deltaMolNumSpecies[kspec]) <= 0.0) {
dx = m_deltaMolNumSpecies[kspec];
} else {
dx = 0.0;
m_deltaMolNumSpecies[kspec] = 0.0;
// HKM Alternative is to not allow ds[] = 0.0 phases
// to pop back into existence. For esthetics, I'm allowing this.
// so that dg < 0.0 phases with zero mole numbers become components.
// This is also better, because that component will be the first
// one to pop into existence if there is a minute quantity of the element.
// This could change in the future.
//if (dg[irxn] >= 0.0 || ds[kspec] <= 0.0) {
if (m_deltaGRxn_new[irxn] >= 0.0 ) {
m_molNumSpecies_new[kspec] = m_molNumSpecies_old[kspec];
m_deltaMolNumSpecies[kspec] = 0.0;
resurrect = false;
#ifdef DEBUG_MODE
sprintf(ANOTE, "dx set to 0, DG flipped sign due to "
"changed initial point");
sprintf(ANOTE, "Species stays zeroed: DG = %11.4E",
m_deltaGRxn_new[irxn]);
if (m_deltaGRxn_new[irxn] < 0.0) {
sprintf(ANOTE, "Species stays zeroed even though dg neg:DG = %11.4E, ds zeroed ",
m_deltaGRxn_new[irxn]);
}
#endif
}
/*
* Form a tentative value of the new species moles
*/
m_molNumSpecies_new[kspec] = m_molNumSpecies_old[kspec] + dx;
/*
* Check for non-positive mole fraction of major species.
* If we find one, we branch to a section below. Then,
* depending upon the outcome, we branch to sections below,
* or we restart the entire iteration.
*/
if (m_molNumSpecies_new[kspec] <= 0.0) {
#ifdef DEBUG_MODE
sprintf(ANOTE, "initial nonpos kmoles= %11.3E",
m_molNumSpecies_new[kspec]);
#endif
/* ************************************************* */
/* *** NON-POSITIVE MOLES OF MAJOR SPECIES ********* */
/* ************************************************* */
/*
* We are here when a tentative value of a mole fraction
* created by a tentative value of M_DELTAMOLNUMSPECIES(*) is negative.
* We branch from here depending upon whether this
* species is in a single species phase or in
* a multispecies phase.
*/
if (! (m_SSPhase[kspec])) {
/*
* Section for multispecies phases:
* - Cut reaction adjustment for positive kmoles of
* major species in multispecies phases.
* Decrease its concentration by a factor of 10.
*/
dx = -0.9 * m_molNumSpecies_old[kspec];
m_deltaMolNumSpecies[kspec] = dx;
m_molNumSpecies_new[kspec] = m_molNumSpecies_old[kspec] + dx;
} else {
/*
* Section for single species phases:
* Calculate a dx that will wipe out the
* moles in the phase.
*/
dx = -m_molNumSpecies_old[kspec];
/*
* Calculate an update that doesn't create a negative mole
* number for a component species. Actually, restrict this
* a little more so that the component values can only be
* reduced by two 99%,
*/
for (j = 0; j < m_numComponents; ++j) {
if (sc_irxn[j] != 0.0) {
wx[j] = m_molNumSpecies_old[j] + sc_irxn[j] * dx;
if (wx[j] <= m_molNumSpecies_old[j] * 0.01 - 1.0E-150) {
dx = MAX(dx, m_molNumSpecies_old[j] * -0.99 / sc_irxn[j]);
for (int j = 0; j < m_numElemConstraints; ++j) {
int elType = m_elType[j];
if (elType == VCS_ELEM_TYPE_ABSPOS) {
double atomComp = m_formulaMatrix[j][kspec];
if (atomComp > 0.0) {
double maxPermissible = m_elemAbundancesGoal[j] / atomComp;
if (maxPermissible < VCS_DELETE_MINORSPECIES_CUTOFF) {
#ifdef DEBUG_MODE
sprintf(ANOTE, "Species stays zeroed even though dG "
"neg, because of %s elemAbund",
m_elementName[j].c_str());
#endif
resurrect = false;
break;
}
}
} else {
wx[j] = m_molNumSpecies_old[j];
}
}
m_molNumSpecies_new[kspec] = m_molNumSpecies_old[kspec] + dx;
if (m_molNumSpecies_new[kspec] > 0.0) {
m_deltaMolNumSpecies[kspec] = dx;
#ifdef DEBUG_MODE
sprintf(ANOTE,
"zeroing SS phase created a neg component species "
"-> reducing step size instead");
#endif
} else {
/*
* We are going to zero the single species phase.
* Set the existence flag
*/
iph = m_phaseID[kspec];
Vphase = m_VolPhaseList[iph];
//Vphase->setExistence(0);
#ifdef DEBUG_MODE
sprintf(ANOTE, "zeroing out SS phase: ");
#endif
/*
* Change the base mole numbers for the iteration.
* We need to do this here, because we have decided
* to eliminate the phase in this special section
* outside the main loop.
*/
m_molNumSpecies_new[kspec] = 0.0;
doPhaseDeleteIph = iph;
doPhaseDeleteKspec = kspec;
}
/*
* Resurrect the species
*/
if (resurrect) {
bool phaseResurrected = false;
if (Vphase->exists() == VCS_PHASE_EXIST_NO) {
//Vphase->setExistence(1);
phaseResurrected = true;
}
--m_numRxnMinorZeroed;
if (phaseResurrected) {
#ifdef DEBUG_MODE
if (m_debug_print_lvl >= 2) {
if (m_speciesStatus[kspec] >= 0) {
plogf(" --- SS species changed to zeroedss: ");
plogf("%-12s", m_speciesName[kspec].c_str());
plogendl();
}
plogf(" --- Zeroed species changed to major: ");
plogf("%-12s\n", m_speciesName[kspec].c_str());
}
#endif
m_speciesStatus[kspec] = VCS_SPECIES_ZEROEDSS;
++m_numRxnMinorZeroed;
allMinorZeroedSpecies = (m_numRxnMinorZeroed == m_numRxnRdc);
for (int kk = 0; kk < m_numSpeciesTot; kk++) {
m_deltaMolNumSpecies[kk] = 0.0;
m_molNumSpecies_new[kk] = m_molNumSpecies_old[kk];
m_speciesStatus[kspec] = VCS_SPECIES_MAJOR;
MajorSpeciesHaveConverged = false;
allMinorZeroedSpecies = false;
} else {
#ifdef DEBUG_MODE
if (m_debug_print_lvl >= 2) {
plogf(" --- Zeroed species changed to minor: ");
plogf("%-12s\n", m_speciesName[kspec].c_str());
}
m_deltaMolNumSpecies[kspec] = dx;
m_molNumSpecies_new[kspec] = 0.0;
for (k = 0; k < m_numComponents; ++k) {
m_deltaMolNumSpecies[k] = 0.0;
}
for (iph = 0; iph < m_numPhases; iph++) {
m_deltaPhaseMoles[iph] = 0.0;
}
#endif
m_speciesStatus[kspec] = VCS_SPECIES_MINOR;
}
if (m_deltaMolNumSpecies[kspec] > 0.0) {
dx = m_deltaMolNumSpecies[kspec] * 0.01;
m_molNumSpecies_new[kspec] = m_molNumSpecies_old[kspec] + dx;
} else {
m_molNumSpecies_new[kspec] = m_totalMolNum * VCS_DELETE_PHASE_CUTOFF * 10.;
dx = m_molNumSpecies_new[kspec] - m_molNumSpecies_old[kspec];
}
m_deltaMolNumSpecies[kspec] = dx;
#ifdef DEBUG_MODE
sprintf(ANOTE, "Born:IC=-1 to IC=1:DG=%11.4E", m_deltaGRxn_new[irxn]);
#endif
} else {
m_molNumSpecies_new[kspec] = m_molNumSpecies_old[kspec];
m_deltaMolNumSpecies[kspec] = 0.0;
dx = 0.0;
}
} else if (m_speciesStatus[kspec] == VCS_SPECIES_MINOR) {
/********************************************************************/
/***************************** MINOR SPECIES ************************/
/********************************************************************/
/*
* Unless ITI isn't equal to zero we zero out changes
* to minor species.
*/
if (iti != 0) {
m_molNumSpecies_new[kspec] = m_molNumSpecies_old[kspec];
m_deltaMolNumSpecies[kspec] = 0.0;
dx = 0.0;
#ifdef DEBUG_MODE
sprintf(ANOTE,"minor species not considered");
if (m_debug_print_lvl >= 2) {
plogf(" --- "); plogf("%-12s", m_speciesName[kspec].c_str());
plogf("%3d%11.4E%11.4E%11.4E | %s",
m_speciesStatus[kspec], m_molNumSpecies_old[kspec], m_molNumSpecies_new[kspec],
m_deltaMolNumSpecies[kspec], ANOTE);
plogendl();
}
#endif
continue;
}
/*
* Minor species alternative calculation
* ---------------------------------------
* This is based upon the following approximation:
* The mole fraction changes due to these reactions don't affect
* the mole numbers of the component species. Therefore the
* following approximation is valid for an ideal solution
* 0 = DG(I) + log(WT(I)/W(I))
* (DG contains the contribution from FF(I) + log(W(I)/TL) )
* Thus,
* WT(I) = W(I) EXP(-DG(I))
* If soldel is true on return, then we branch to the section
* that deletes a species from the current set of active species.
*/
#ifdef DEBUG_MODE
dx = vcs_minor_alt_calc(kspec, irxn, &soldel, ANOTE);
#else
dx = vcs_minor_alt_calc(kspec, irxn, &soldel);
#endif
m_deltaMolNumSpecies[kspec] = dx;
m_molNumSpecies_new[kspec] = m_molNumSpecies_old[kspec] + dx;
if (soldel) {
/*******************************************************************/
/***** DELETE MINOR SPECIES LESS THAN VCS_DELETE_SPECIES_CUTOFF */
/***** MOLE NUMBER */
/*******************************************************************/
#ifdef DEBUG_MODE
if (m_debug_print_lvl >= 2) {
plogf(" --- Delete minor species in multispec phase: %-12s",
m_speciesName[kspec].c_str());
plogendl();
}
#endif
m_deltaMolNumSpecies[kspec] = 0.0;
/*
* Delete species, kspec. The alternate return is for the case
* where all species become deleted. Then, we need to
* branch to the code where we reevaluate the deletion
* of all species.
*/
lnospec = vcs_delete_species(kspec);
if (lnospec) goto L_RECHECK_DELETED;
/*
* Go back to consider the next species in the list.
* Note, however, that the next species in the list is now
* in slot l. In deleting the previous species L, We have
* exchanged slot MR with slot l, and then have
* decremented MR.
* Therefore, we will decrement the species counter, here.
*/
--irxn;
#ifdef DEBUG_MODE
goto L_MAIN_LOOP_END_NO_PRINT;
#else
goto L_MAIN_LOOP_END;
#endif
}
} else {
/********************************************************************/
/*********************** MAJOR SPECIES ******************************/
/********************************************************************/
#ifdef DEBUG_MODE
sprintf(ANOTE, "Normal Major Calc");
#endif
/*
* Check for superconvergence of the formation reaction. Do
* nothing if it is superconverged. Skip to the end of the
* irxn loop if it is superconverged.
*/
if (fabs(m_deltaGRxn_new[irxn]) <= m_tolmaj2) {
m_molNumSpecies_new[kspec] = m_molNumSpecies_old[kspec];
m_deltaMolNumSpecies[kspec] = 0.0;
dx = 0.0;
#ifdef DEBUG_MODE
sprintf(ANOTE, "major species is converged");
if (m_debug_print_lvl >= 2) {
plogf(" --- "); plogf("%-12s", m_speciesName[kspec].c_str());
plogf("%3d%11.4E%11.4E%11.4E | %s",
m_speciesStatus[kspec], m_molNumSpecies_old[kspec], m_molNumSpecies_new[kspec],
m_deltaMolNumSpecies[kspec], ANOTE);
plogendl();
}
#endif
continue;
}
/*
* Set the initial step size, dx, equal to the value produced
* by the routine, vcs_RxnStepSize().
*
* Note the multiplition logic is to make sure that
* dg[] didn't change sign due to w[] changing in the
* middle of the iteration. (it can if a single species
* phase goes out of existence).
*/
if ((m_deltaGRxn_new[irxn] * m_deltaMolNumSpecies[kspec]) <= 0.0) {
dx = m_deltaMolNumSpecies[kspec];
} else {
dx = 0.0;
m_deltaMolNumSpecies[kspec] = 0.0;
#ifdef DEBUG_MODE
sprintf(ANOTE, "dx set to 0, DG flipped sign due to "
"changed initial point");
#endif
}
/*
* Form a tentative value of the new species moles
*/
m_molNumSpecies_new[kspec] = m_molNumSpecies_old[kspec] + dx;
/*
* Check for non-positive mole fraction of major species.
* If we find one, we branch to a section below. Then,
* depending upon the outcome, we branch to sections below,
* or we restart the entire iteration.
*/
if (m_molNumSpecies_new[kspec] <= 0.0) {
#ifdef DEBUG_MODE
sprintf(ANOTE, "initial nonpos kmoles= %11.3E",
m_molNumSpecies_new[kspec]);
#endif
/* ************************************************* */
/* *** NON-POSITIVE MOLES OF MAJOR SPECIES ********* */
/* ************************************************* */
/*
* We are here when a tentative value of a mole fraction
* created by a tentative value of M_DELTAMOLNUMSPECIES(*) is negative.
* We branch from here depending upon whether this
* species is in a single species phase or in
* a multispecies phase.
*/
if (! (m_SSPhase[kspec])) {
/*
* Section for multispecies phases:
* - Cut reaction adjustment for positive kmoles of
* major species in multispecies phases.
* Decrease its concentration by a factor of 10.
*/
dx = -0.9 * m_molNumSpecies_old[kspec];
m_deltaMolNumSpecies[kspec] = dx;
m_molNumSpecies_new[kspec] = m_molNumSpecies_old[kspec] + dx;
} else {
/*
* Section for single species phases:
* Calculate a dx that will wipe out the
* moles in the phase.
*/
dx = -m_molNumSpecies_old[kspec];
/*
* Calculate an update that doesn't create a negative mole
* number for a component species. Actually, restrict this
* a little more so that the component values can only be
* reduced by two 99%,
*/
for (j = 0; j < m_numComponents; ++j) {
if (sc_irxn[j] != 0.0) {
wx[j] = m_molNumSpecies_old[j] + sc_irxn[j] * dx;
if (wx[j] <= m_molNumSpecies_old[j] * 0.01 - 1.0E-150) {
dx = MAX(dx, m_molNumSpecies_old[j] * -0.99 / sc_irxn[j]);
}
} else {
wx[j] = m_molNumSpecies_old[j];
}
}
m_molNumSpecies_new[kspec] = m_molNumSpecies_old[kspec] + dx;
if (m_molNumSpecies_new[kspec] > 0.0) {
m_deltaMolNumSpecies[kspec] = dx;
#ifdef DEBUG_MODE
sprintf(ANOTE,
"zeroing SS phase created a neg component species "
"-> reducing step size instead");
#endif
} else {
/*
* We are going to zero the single species phase.
* Set the existence flag
*/
iph = m_phaseID[kspec];
Vphase = m_VolPhaseList[iph];
//Vphase->setExistence(0);
#ifdef DEBUG_MODE
sprintf(ANOTE, "zeroing out SS phase: ");
#endif
/*
* Change the base mole numbers for the iteration.
* We need to do this here, because we have decided
* to eliminate the phase in this special section
* outside the main loop.
*/
m_molNumSpecies_new[kspec] = 0.0;
doPhaseDeleteIph = iph;
doPhaseDeleteKspec = kspec;
#ifdef DEBUG_MODE
if (m_debug_print_lvl >= 2) {
if (m_speciesStatus[kspec] >= 0) {
plogf(" --- SS species changed to zeroedss: ");
plogf("%-12s", m_speciesName[kspec].c_str());
plogendl();
}
}
#endif
m_speciesStatus[kspec] = VCS_SPECIES_ZEROEDSS;
++m_numRxnMinorZeroed;
allMinorZeroedSpecies = (m_numRxnMinorZeroed == m_numRxnRdc);
for (int kk = 0; kk < m_numSpeciesTot; kk++) {
m_deltaMolNumSpecies[kk] = 0.0;
m_molNumSpecies_new[kk] = m_molNumSpecies_old[kk];
}
m_deltaMolNumSpecies[kspec] = dx;
m_molNumSpecies_new[kspec] = 0.0;
for (k = 0; k < m_numComponents; ++k) {
m_deltaMolNumSpecies[k] = 0.0;
}
for (iph = 0; iph < m_numPhases; iph++) {
m_deltaPhaseMoles[iph] = 0.0;
}
}
}
}
#ifdef VCS_LINE_SEARCH
/*********************************************************************/
/*** LINE SEARCH ALGORITHM FOR MAJOR SPECIES IN NON-IDEAL PHASES *****/
/*********************************************************************/
/*
* Skip the line search if we are birthing a species
*/
if ((dx != 0.0) &&
(m_molNumSpecies_old[kspec] > 0.0) &&
(doPhaseDeleteIph == -1) &&
(m_speciesUnknownType[kspec] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE)) {
double dx_old = dx;
/*********************************************************************/
/*** LINE SEARCH ALGORITHM FOR MAJOR SPECIES IN NON-IDEAL PHASES *****/
/*********************************************************************/
/*
* Skip the line search if we are birthing a species
*/
if ((dx != 0.0) &&
(m_molNumSpecies_old[kspec] > 0.0) &&
(doPhaseDeleteIph == -1) &&
(m_speciesUnknownType[kspec] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE)) {
double dx_old = dx;
#ifdef DEBUG_MODE
dx = vcs_line_search(irxn, dx_old, ANOTE);
dx = vcs_line_search(irxn, dx_old, ANOTE);
#else
dx = vcs_line_search(irxn, dx_old);
dx = vcs_line_search(irxn, dx_old);
#endif
vcs_setFlagsVolPhases(false, VCS_STATECALC_NEW);
}
m_deltaMolNumSpecies[kspec] = dx;
vcs_setFlagsVolPhases(false, VCS_STATECALC_NEW);
}
m_deltaMolNumSpecies[kspec] = dx;
#endif
} /* End of Loop on ic[irxn] -> the type of species */
}/* End of Loop on ic[irxn] -> the type of species */
}
/***********************************************************************/
/****** CALCULATE KMOLE NUMBER CHANGE FOR THE COMPONENT BASIS **********/
/***********************************************************************/
@ -4748,7 +4791,8 @@ namespace VCSnonideal {
* This should be implemented.
*/
int k;
if (alterZeroedPhases) {
//alterZeroedPhases = false;
if (alterZeroedPhases && false) {
for (iph = 0; iph < m_numPhases; iph++) {
lneed = FALSE;
vcs_VolPhase *Vphase = m_VolPhaseList[iph];

View file

@ -75,8 +75,10 @@ namespace Cantera {
MC_apCut_(0.0),
MC_bpCut_(0.0),
MC_cpCut_(0.0),
CROP_ln_gamma_o_min(-25.0),
CROP_ln_gamma_k_max(23.0),
CROP_ln_gamma_o_min(-10.0),
CROP_ln_gamma_o_max(3.0),
CROP_ln_gamma_k_min(-5.0),
CROP_ln_gamma_k_max(15.0),
m_debugCalc(0)
{
for (int i = 0; i < 17; i++) {
@ -130,8 +132,10 @@ namespace Cantera {
MC_apCut_(0.0),
MC_bpCut_(0.0),
MC_cpCut_(0.0),
CROP_ln_gamma_o_min(-25.0),
CROP_ln_gamma_k_max(23.0),
CROP_ln_gamma_o_min(-10.0),
CROP_ln_gamma_o_max(3.0),
CROP_ln_gamma_k_min(-5.0),
CROP_ln_gamma_k_max(15.0),
m_debugCalc(0)
{
for (int i = 0; i < 17; i++) {
@ -179,8 +183,10 @@ namespace Cantera {
MC_apCut_(0.0),
MC_bpCut_(0.0),
MC_cpCut_(0.0),
CROP_ln_gamma_o_min(-25.0),
CROP_ln_gamma_k_max(23.0),
CROP_ln_gamma_o_min(-10.0),
CROP_ln_gamma_o_max(3.0),
CROP_ln_gamma_k_min(-5.0),
CROP_ln_gamma_k_max(15.0),
m_debugCalc(0)
{
for (int i = 0; i < 17; i++) {
@ -234,8 +240,10 @@ namespace Cantera {
MC_apCut_(0.0),
MC_bpCut_(0.0),
MC_cpCut_(0.0),
CROP_ln_gamma_o_min(-25.0),
CROP_ln_gamma_k_max(23.0),
CROP_ln_gamma_o_min(-10.0),
CROP_ln_gamma_o_max(3.0),
CROP_ln_gamma_k_min(-5.0),
CROP_ln_gamma_k_max(15.0),
m_debugCalc(0)
{
/*
@ -389,6 +397,8 @@ namespace Cantera {
MC_bpCut_ = b.MC_bpCut_;
MC_cpCut_ = b.MC_cpCut_;
CROP_ln_gamma_o_min = b.CROP_ln_gamma_o_min;
CROP_ln_gamma_o_max = b.CROP_ln_gamma_o_max;
CROP_ln_gamma_k_min = b.CROP_ln_gamma_k_min;
CROP_ln_gamma_k_max = b.CROP_ln_gamma_k_max;
m_CounterIJ = b.m_CounterIJ;
m_molalitiesCropped = b.m_molalitiesCropped;
@ -463,8 +473,10 @@ namespace Cantera {
MC_apCut_(0.0),
MC_bpCut_(0.0),
MC_cpCut_(0.0),
CROP_ln_gamma_o_min(-25.0),
CROP_ln_gamma_k_max(23.0),
CROP_ln_gamma_o_min(-10.0),
CROP_ln_gamma_o_max(3.0),
CROP_ln_gamma_k_min(-5.0),
CROP_ln_gamma_k_max(15.0),
m_debugCalc(0)
{
if (testProb != 1) {
@ -1812,14 +1824,22 @@ namespace Cantera {
for (int k = 1; k < m_kk; k++) {
m_lnActCoeffMolal_Unscaled[k] += IMS_lnActCoeffMolal_[k];
if (m_lnActCoeffMolal_Unscaled[k] > (CROP_ln_gamma_k_max + lnxs)) {
m_lnActCoeffMolal_Unscaled[k] = CROP_ln_gamma_k_max + lnxs;
if (m_lnActCoeffMolal_Unscaled[k] > (CROP_ln_gamma_k_max)) {
m_lnActCoeffMolal_Unscaled[k] = CROP_ln_gamma_k_max;
}
if (m_lnActCoeffMolal_Unscaled[k] < (CROP_ln_gamma_k_min - 2.5 *lnxs)) {
// -1.0 and -1.5 caused multiple solutions
m_lnActCoeffMolal_Unscaled[k] = CROP_ln_gamma_k_min - 2.5 * lnxs;
}
}
m_lnActCoeffMolal_Unscaled[0] += (IMS_lnActCoeffMolal_[0] - lnActCoeffMolal0);
if (m_lnActCoeffMolal_Unscaled[0] < CROP_ln_gamma_o_min - lnxs) {
m_lnActCoeffMolal_Unscaled[0] = CROP_ln_gamma_o_min - lnxs;
if (m_lnActCoeffMolal_Unscaled[0] < CROP_ln_gamma_o_min) {
m_lnActCoeffMolal_Unscaled[0] = CROP_ln_gamma_o_min;
}
if (m_lnActCoeffMolal_Unscaled[0] > CROP_ln_gamma_o_max) {
// -0.5 caused multiple solutions
m_lnActCoeffMolal_Unscaled[0] = CROP_ln_gamma_o_max;
}
/*

View file

@ -3194,9 +3194,12 @@ namespace Cantera {
doublereal MC_cpCut_;
doublereal CROP_ln_gamma_o_min;
doublereal CROP_ln_gamma_o_max;
doublereal CROP_ln_gamma_k_min;
doublereal CROP_ln_gamma_k_max;
//! Local error routine
/*!
* @param msg print out a message and error exit