/*! * This is done by running * each reaction as far forward or backward as possible, subject * to the constraint that all mole numbers remain * non-negative. Reactions for which \f$ \Delta \mu^0 \f$ are * positive are run in reverse, and ones for which it is negative * are run in the forward direction. The end result is equivalent * to solving the linear programming problem of minimizing the * linear Gibbs function subject to the element and * non-negativity constraints. */ int VCS_SOLVE::vcs_setMolesLinProg() { int ik, irxn; double test = -1.0E-10; #ifdef DEBUG_MODE std::string pprefix(" --- seMolesLinProg "); if (m_debug_print_lvl >= 2) { plogf(" --- call setInitialMoles\n"); } #endif // m_mu are standard state chemical potentials // Boolean on the end specifies standard chem potentials // m_mix->getValidChemPotentials(not_mu, DATA_PTR(m_mu), true); // -> This is already done coming into the routine. double dg_rt; int idir; double nu; double delta_xi, dxi_min = 1.0e10; bool redo = true; int jcomp; int retn; int iter = 0; bool abundancesOK = true; int usedZeroedSpecies; std::vector<double> sm(m_numElemConstraints*m_numElemConstraints, 0.0); std::vector<double> ss(m_numElemConstraints, 0.0); std::vector<double> sa(m_numElemConstraints, 0.0); std::vector<double> wx(m_numElemConstraints, 0.0); std::vector<double> aw(m_numSpeciesTot, 0.0); for (ik = 0; ik < m_numSpeciesTot; ik++) { if (m_speciesUnknownType[ik] != VCS_SPECIES_INTERFACIALVOLTAGE) { m_molNumSpecies_old[ik] = MAX(0.0, m_molNumSpecies_old[ik]); } } #ifdef DEBUG_MODE if (m_debug_print_lvl >= 2) { printProgress(m_speciesName, m_molNumSpecies_old, m_SSfeSpecies); } #endif while (redo) { if (!vcs_elabcheck(0)) { #ifdef DEBUG_MODE if (m_debug_print_lvl >= 2) { plogf("%s Mole numbers failing element abundances\n", pprefix.c_str()); plogf("%sCall vcs_elcorr to attempt fix\n", pprefix.c_str()); } #endif retn = vcs_elcorr(VCS_DATA_PTR(sm), VCS_DATA_PTR(wx)); if (retn >= 2) { abundancesOK = false; } else { abundancesOK = true; } } else { abundancesOK = true; } /* * Now find the optimized basis that spans the stoichiometric * coefficient matrix, based on the current composition, m_molNumSpecies_old[] * We also calculate sc[][], the reaction matrix. */ retn = vcs_basopt(FALSE, VCS_DATA_PTR(aw), VCS_DATA_PTR(sa), VCS_DATA_PTR(sm), VCS_DATA_PTR(ss), test, &usedZeroedSpecies); if (retn != VCS_SUCCESS) return retn; #ifdef DEBUG_MODE if (m_debug_print_lvl >= 2) { plogf("iteration %d\n", iter); } #endif redo = false; iter++; if (iter > 15) break; // loop over all reactions for (irxn = 0; irxn < m_numRxnTot; irxn++) { // dg_rt is the Delta_G / RT value for the reaction ik = m_numComponents + irxn; dg_rt = m_SSfeSpecies[ik]; dxi_min = 1.0e10; const double *sc_irxn = m_stoichCoeffRxnMatrix[irxn]; for (jcomp = 0; jcomp < m_numElemConstraints; jcomp++) { dg_rt += m_SSfeSpecies[jcomp] * sc_irxn[jcomp]; } // fwd or rev direction. // idir > 0 implies increasing the current species // idir < 0 implies decreasing the current species idir = (dg_rt < 0.0 ? 1 : -1); if (idir < 0) { dxi_min = m_molNumSpecies_old[ik]; } for (jcomp = 0; jcomp < m_numComponents; jcomp++) { nu = sc_irxn[jcomp]; // set max change in progress variable by // non-negativity requirement if (nu*idir < 0) { delta_xi = fabs(m_molNumSpecies_old[jcomp]/nu); // if a component has nearly zero moles, redo // with a new set of components if (!redo) { if (delta_xi < 1.0e-10 && (m_molNumSpecies_old[ik] >= 1.0E-10)) { #ifdef DEBUG_MODE if (m_debug_print_lvl >= 2) { plogf(" --- Component too small: %s\n", m_speciesName[jcomp].c_str()); } #endif redo = true; } } if (delta_xi < dxi_min) dxi_min = delta_xi; } } // step the composition by dxi_min, check against zero, since // we are zeroing components and species on every step. // Redo the iteration, if a component went from positive to zero on this step. double dsLocal = idir*dxi_min; m_molNumSpecies_old[ik] += dsLocal; m_molNumSpecies_old[ik] = MAX(0.0, m_molNumSpecies_old[ik]); for (jcomp = 0; jcomp < m_numComponents; jcomp++) { bool full = false; if (m_molNumSpecies_old[jcomp] > 1.0E-15) { full = true; } m_molNumSpecies_old[jcomp] += sc_irxn[jcomp] * dsLocal; m_molNumSpecies_old[jcomp] = MAX(0.0, m_molNumSpecies_old[jcomp]); if (full) { if (m_molNumSpecies_old[jcomp] < 1.0E-60) { redo = true; } } } } // set the moles of the phase objects to match // updateMixMoles(); // Update the phase objects with the contents of the m_molNumSpecies_old vector // vcs_updateVP(0); #ifdef DEBUG_MODE if (m_debug_print_lvl >= 2) { printProgress(m_speciesName, m_molNumSpecies_old, m_SSfeSpecies); } #endif } #ifdef DEBUG_MODE if (m_debug_print_lvl == 1) { printProgress(m_speciesName, m_molNumSpecies_old, m_SSfeSpecies); plogf(" --- setInitialMoles end\n"); } #endif retn = 0; if (!abundancesOK) { retn = -1; } else if (iter > 15) { retn = 1; } return retn; }
int VCS_SOLVE::vcs_elcorr(double aa[], double x[]) /************************************************************************** * * vcs_elcorr: * * This subroutine corrects for element abundances. At the end of the * surbroutine, the total moles in all phases are recalculated again, * because we have changed the number of moles in this routine. * * Input * -> temporary work vectors: * aa[ne*ne] * x[ne] * * Return Values: * 0 = Nothing of significance happened, * Element abundances were and still are good. * 1 = The solution changed significantly; * The element abundances are now good. * 2 = The solution changed significantly, * The element abundances are still bad. * 3 = The solution changed significantly, * The element abundances are still bad and a component * species got zeroed out. * * Internal data to be worked on:: * * ga Current element abundances * m_elemAbundancesGoal Required elemental abundances * m_molNumSpecies_old Current mole number of species. * m_formulaMatrix[][] Formular matrix of the species * ne Number of elements * nc Number of components. * * NOTES: * This routine is turning out to be very problematic. There are * lots of special cases and problems with zeroing out species. * * Still need to check out when we do loops over nc vs. ne. * *************************************************************************/ { int i, j, retn = 0, kspec, goodSpec, its; double xx, par, saveDir, dir; #ifdef DEBUG_MODE double l2before = 0.0, l2after = 0.0; std::vector<double> ga_save(m_numElemConstraints, 0.0); vcs_dcopy(VCS_DATA_PTR(ga_save), VCS_DATA_PTR(m_elemAbundances), m_numElemConstraints); if (m_debug_print_lvl >= 2) { plogf(" --- vcsc_elcorr: Element abundances correction routine"); if (m_numElemConstraints != m_numComponents) { plogf(" (m_numComponents != m_numElemConstraints)"); } plogf("\n"); } for (i = 0; i < m_numElemConstraints; ++i) { x[i] = m_elemAbundances[i] - m_elemAbundancesGoal[i]; } l2before = 0.0; for (i = 0; i < m_numElemConstraints; ++i) { l2before += x[i] * x[i]; } l2before = sqrt(l2before/m_numElemConstraints); #endif /* * Special section to take out single species, single component, * moles. These are species which have non-zero entries in the * formula matrix, and no other species have zero values either. * */ int numNonZero = 0; bool changed = false; bool multisign = false; for (i = 0; i < m_numElemConstraints; ++i) { numNonZero = 0; multisign = false; for (kspec = 0; kspec < m_numSpeciesTot; kspec++) { if (m_speciesUnknownType[kspec] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) { double eval = m_formulaMatrix[i][kspec]; if (eval < 0.0) { multisign = true; } if (eval != 0.0) { numNonZero++; } } } if (!multisign) { if (numNonZero < 2) { for (kspec = 0; kspec < m_numSpeciesTot; kspec++) { if (m_speciesUnknownType[kspec] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) { double eval = m_formulaMatrix[i][kspec]; if (eval > 0.0) { m_molNumSpecies_old[kspec] = m_elemAbundancesGoal[i] / eval; changed = true; } } } } else { int numCompNonZero = 0; int compID = -1; for (kspec = 0; kspec < m_numComponents; kspec++) { if (m_speciesUnknownType[kspec] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) { double eval = m_formulaMatrix[i][kspec]; if (eval > 0.0) { compID = kspec; numCompNonZero++; } } } if (numCompNonZero == 1) { double diff = m_elemAbundancesGoal[i]; for (kspec = m_numComponents; kspec < m_numSpeciesTot; kspec++) { if (m_speciesUnknownType[kspec] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) { double eval = m_formulaMatrix[i][kspec]; diff -= eval * m_molNumSpecies_old[kspec]; } m_molNumSpecies_old[compID] = MAX(0.0,diff/m_formulaMatrix[i][compID]); changed = true; } } } } } if (changed) { vcs_elab(); } /* * Section to check for maximum bounds errors on all species * due to elements. * This may only be tried on element types which are VCS_ELEM_TYPE_ABSPOS. * This is because no other species may have a negative number of these. * * Note, also we can do this over ne, the number of elements, not just * the number of components. */ changed = false; for (i = 0; i < m_numElemConstraints; ++i) { int elType = m_elType[i]; if (elType == VCS_ELEM_TYPE_ABSPOS) { for (kspec = 0; kspec < m_numSpeciesTot; kspec++) { if (m_speciesUnknownType[kspec] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) { double atomComp = m_formulaMatrix[i][kspec]; if (atomComp > 0.0) { double maxPermissible = m_elemAbundancesGoal[i] / atomComp; if (m_molNumSpecies_old[kspec] > maxPermissible) { #ifdef DEBUG_MODE if (m_debug_print_lvl >= 3) { plogf(" --- vcs_elcorr: Reduced species %s from %g to %g " "due to %s max bounds constraint\n", m_speciesName[kspec].c_str(), m_molNumSpecies_old[kspec], maxPermissible, m_elementName[i].c_str()); } #endif m_molNumSpecies_old[kspec] = maxPermissible; changed = true; if (m_molNumSpecies_old[kspec] < VCS_DELETE_MINORSPECIES_CUTOFF) { m_molNumSpecies_old[kspec] = 0.0; if (m_SSPhase[kspec]) { m_speciesStatus[kspec] = VCS_SPECIES_ZEROEDSS; } else { m_speciesStatus[kspec] = VCS_SPECIES_ACTIVEBUTZERO; } #ifdef DEBUG_MODE if (m_debug_print_lvl >= 2) { plogf(" --- vcs_elcorr: Zeroed species %s and changed " "status to %d due to max bounds constraint\n", m_speciesName[kspec].c_str(), m_speciesStatus[kspec]); } #endif } } } } } } } // Recalculate the element abundances if something has changed. if (changed) { vcs_elab(); } /* * Ok, do the general case. Linear algebra problem is * of length nc, not ne, as there may be degenerate rows when * nc .ne. ne. */ for (i = 0; i < m_numComponents; ++i) { x[i] = m_elemAbundances[i] - m_elemAbundancesGoal[i]; if (fabs(x[i]) > 1.0E-13) retn = 1; for (j = 0; j < m_numComponents; ++j) { aa[j + i*m_numElemConstraints] = m_formulaMatrix[j][i]; } } i = vcsUtil_mlequ(aa, m_numElemConstraints, m_numComponents, x, 1); if (i == 1) { plogf("vcs_elcorr ERROR: mlequ returned error condition\n"); return VCS_FAILED_CONVERGENCE; } /* * Now apply the new direction without creating negative species. */ par = 0.5; for (i = 0; i < m_numComponents; ++i) { if (m_molNumSpecies_old[i] > 0.0) { xx = -x[i] / m_molNumSpecies_old[i]; if (par < xx) par = xx; } } if (par > 100.0) { par = 100.0; } par = 1.0 / par; if (par < 1.0 && par > 0.0) { retn = 2; par *= 0.9999; for (i = 0; i < m_numComponents; ++i) { double tmp = m_molNumSpecies_old[i] + par * x[i]; if (tmp > 0.0) { m_molNumSpecies_old[i] = tmp; } else { if (m_SSPhase[i]) { m_molNumSpecies_old[i] = 0.0; } else { m_molNumSpecies_old[i] = m_molNumSpecies_old[i] * 0.0001; } } } } else { for (i = 0; i < m_numComponents; ++i) { double tmp = m_molNumSpecies_old[i] + x[i]; if (tmp > 0.0) { m_molNumSpecies_old[i] = tmp; } else { if (m_SSPhase[i]) { m_molNumSpecies_old[i] = 0.0; } else { m_molNumSpecies_old[i] = m_molNumSpecies_old[i] * 0.0001; } } } } /* * We have changed the element abundances. Calculate them again */ vcs_elab(); /* * We have changed the total moles in each phase. Calculate them again */ vcs_tmoles(); /* * Try some ad hoc procedures for fixing the problem */ if (retn >= 2) { /* * First find a species whose adjustment is a win-win * situation. */ for (kspec = 0; kspec < m_numSpeciesTot; kspec++) { if (m_speciesUnknownType[kspec] == VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) { continue; } saveDir = 0.0; goodSpec = TRUE; for (i = 0; i < m_numComponents; ++i) { dir = m_formulaMatrix[i][kspec] * (m_elemAbundancesGoal[i] - m_elemAbundances[i]); if (fabs(dir) > 1.0E-10) { if (dir > 0.0) { if (saveDir < 0.0) { goodSpec = FALSE; break; } } else { if (saveDir > 0.0) { goodSpec = FALSE; break; } } saveDir = dir; } else { if (m_formulaMatrix[i][kspec] != 0.) { goodSpec = FALSE; break; } } } if (goodSpec) { its = 0; xx = 0.0; for (i = 0; i < m_numComponents; ++i) { if (m_formulaMatrix[i][kspec] != 0.0) { xx += (m_elemAbundancesGoal[i] - m_elemAbundances[i]) / m_formulaMatrix[i][kspec]; its++; } } if (its > 0) xx /= its; m_molNumSpecies_old[kspec] += xx; m_molNumSpecies_old[kspec] = MAX(m_molNumSpecies_old[kspec], 1.0E-10); /* * If we are dealing with a deleted species, then * we need to reinsert it into the active list. */ if (kspec >= m_numSpeciesRdc) { vcs_reinsert_deleted(kspec); m_molNumSpecies_old[m_numSpeciesRdc - 1] = xx; vcs_elab(); goto L_CLEANUP; } vcs_elab(); } } } if (vcs_elabcheck(0)) { retn = 1; goto L_CLEANUP; } for (i = 0; i < m_numElemConstraints; ++i) { if (m_elType[i] == VCS_ELEM_TYPE_CHARGENEUTRALITY || (m_elType[i] == VCS_ELEM_TYPE_ABSPOS && m_elemAbundancesGoal[i] == 0.0)) { for (kspec = 0; kspec < m_numSpeciesRdc; kspec++) { if (m_elemAbundances[i] > 0.0) { if (m_formulaMatrix[i][kspec] < 0.0) { m_molNumSpecies_old[kspec] -= m_elemAbundances[i] / m_formulaMatrix[i][kspec] ; if (m_molNumSpecies_old[kspec] < 0.0) { m_molNumSpecies_old[kspec] = 0.0; } vcs_elab(); break; } } if (m_elemAbundances[i] < 0.0) { if (m_formulaMatrix[i][kspec] > 0.0) { m_molNumSpecies_old[kspec] -= m_elemAbundances[i] / m_formulaMatrix[i][kspec]; if (m_molNumSpecies_old[kspec] < 0.0) { m_molNumSpecies_old[kspec] = 0.0; } vcs_elab(); break; } } } } } if (vcs_elabcheck(1)) { retn = 1; goto L_CLEANUP; } /* * For electron charges element types, we try positive deltas * in the species concentrations to match the desired * electron charge exactly. */ for (i = 0; i < m_numElemConstraints; ++i) { double dev = m_elemAbundancesGoal[i] - m_elemAbundances[i]; if (m_elType[i] == VCS_ELEM_TYPE_ELECTRONCHARGE && (fabs(dev) > 1.0E-300)) { bool useZeroed = true; for (kspec = 0; kspec < m_numSpeciesRdc; kspec++) { if (dev < 0.0) { if (m_formulaMatrix[i][kspec] < 0.0) { if (m_molNumSpecies_old[kspec] > 0.0) { useZeroed = false; } } } else { if (m_formulaMatrix[i][kspec] > 0.0) { if (m_molNumSpecies_old[kspec] > 0.0) { useZeroed = false; } } } } for (kspec = 0; kspec < m_numSpeciesRdc; kspec++) { if (m_molNumSpecies_old[kspec] > 0.0 || useZeroed) { if (dev < 0.0) { if (m_formulaMatrix[i][kspec] < 0.0) { double delta = dev / m_formulaMatrix[i][kspec] ; m_molNumSpecies_old[kspec] += delta; if (m_molNumSpecies_old[kspec] < 0.0) { m_molNumSpecies_old[kspec] = 0.0; } vcs_elab(); break; } } if (dev > 0.0) { if (m_formulaMatrix[i][kspec] > 0.0) { double delta = dev / m_formulaMatrix[i][kspec] ; m_molNumSpecies_old[kspec] += delta; if (m_molNumSpecies_old[kspec] < 0.0) { m_molNumSpecies_old[kspec] = 0.0; } vcs_elab(); break; } } } } } } if (vcs_elabcheck(1)) { retn = 1; goto L_CLEANUP; } L_CLEANUP: ; vcs_tmoles(); #ifdef DEBUG_MODE l2after = 0.0; for (i = 0; i < m_numElemConstraints; ++i) { l2after += SQUARE(m_elemAbundances[i] - m_elemAbundancesGoal[i]); } l2after = sqrt(l2after/m_numElemConstraints); if (m_debug_print_lvl >= 2) { plogf(" --- Elem_Abund: Correct Initial " " Final\n"); for (i = 0; i < m_numElemConstraints; ++i) { plogf(" --- "); plogf("%-2.2s", m_elementName[i].c_str()); plogf(" %20.12E %20.12E %20.12E\n", m_elemAbundancesGoal[i], ga_save[i], m_elemAbundances[i]); } plogf(" --- Diff_Norm: %20.12E %20.12E\n", l2before, l2after); } #endif return retn; }
int VCS_SOLVE::vcs_setMolesLinProg() { size_t ik, irxn; double test = -1.0E-10; if (DEBUG_MODE_ENABLED && m_debug_print_lvl >= 2) { plogf(" --- call setInitialMoles\n"); } double dg_rt; int idir; double nu; double delta_xi, dxi_min = 1.0e10; bool redo = true; int retn; int iter = 0; bool abundancesOK = true; bool usedZeroedSpecies; vector_fp sm(m_numElemConstraints*m_numElemConstraints, 0.0); vector_fp ss(m_numElemConstraints, 0.0); vector_fp sa(m_numElemConstraints, 0.0); vector_fp wx(m_numElemConstraints, 0.0); vector_fp aw(m_numSpeciesTot, 0.0); for (ik = 0; ik < m_numSpeciesTot; ik++) { if (m_speciesUnknownType[ik] != VCS_SPECIES_INTERFACIALVOLTAGE) { m_molNumSpecies_old[ik] = max(0.0, m_molNumSpecies_old[ik]); } } if (DEBUG_MODE_ENABLED && m_debug_print_lvl >= 2) { printProgress(m_speciesName, m_molNumSpecies_old, m_SSfeSpecies); } while (redo) { if (!vcs_elabcheck(0)) { if (DEBUG_MODE_ENABLED && m_debug_print_lvl >= 2) { plogf(" --- seMolesLinProg Mole numbers failing element abundances\n"); plogf(" --- seMolesLinProg Call vcs_elcorr to attempt fix\n"); } retn = vcs_elcorr(&sm[0], &wx[0]); if (retn >= 2) { abundancesOK = false; } else { abundancesOK = true; } } else { abundancesOK = true; } /* * Now find the optimized basis that spans the stoichiometric * coefficient matrix, based on the current composition, m_molNumSpecies_old[] * We also calculate sc[][], the reaction matrix. */ retn = vcs_basopt(false, &aw[0], &sa[0], &sm[0], &ss[0], test, &usedZeroedSpecies); if (retn != VCS_SUCCESS) { return retn; } if (DEBUG_MODE_ENABLED && m_debug_print_lvl >= 2) { plogf("iteration %d\n", iter); } redo = false; iter++; if (iter > 15) { break; } // loop over all reactions for (irxn = 0; irxn < m_numRxnTot; irxn++) { // dg_rt is the Delta_G / RT value for the reaction ik = m_numComponents + irxn; dg_rt = m_SSfeSpecies[ik]; dxi_min = 1.0e10; const double* sc_irxn = m_stoichCoeffRxnMatrix.ptrColumn(irxn); for (size_t jcomp = 0; jcomp < m_numElemConstraints; jcomp++) { dg_rt += m_SSfeSpecies[jcomp] * sc_irxn[jcomp]; } // fwd or rev direction. // idir > 0 implies increasing the current species // idir < 0 implies decreasing the current species idir = (dg_rt < 0.0 ? 1 : -1); if (idir < 0) { dxi_min = m_molNumSpecies_old[ik]; } for (size_t jcomp = 0; jcomp < m_numComponents; jcomp++) { nu = sc_irxn[jcomp]; // set max change in progress variable by // non-negativity requirement if (nu*idir < 0) { delta_xi = fabs(m_molNumSpecies_old[jcomp]/nu); // if a component has nearly zero moles, redo // with a new set of components if (!redo && delta_xi < 1.0e-10 && (m_molNumSpecies_old[ik] >= 1.0E-10)) { if (DEBUG_MODE_ENABLED && m_debug_print_lvl >= 2) { plogf(" --- Component too small: %s\n", m_speciesName[jcomp]); } redo = true; } dxi_min = std::min(dxi_min, delta_xi); } } // step the composition by dxi_min, check against zero, since // we are zeroing components and species on every step. // Redo the iteration, if a component went from positive to zero on this step. double dsLocal = idir*dxi_min; m_molNumSpecies_old[ik] += dsLocal; m_molNumSpecies_old[ik] = max(0.0, m_molNumSpecies_old[ik]); for (size_t jcomp = 0; jcomp < m_numComponents; jcomp++) { bool full = false; if (m_molNumSpecies_old[jcomp] > 1.0E-15) { full = true; } m_molNumSpecies_old[jcomp] += sc_irxn[jcomp] * dsLocal; m_molNumSpecies_old[jcomp] = max(0.0, m_molNumSpecies_old[jcomp]); if (full && m_molNumSpecies_old[jcomp] < 1.0E-60) { redo = true; } } } if (DEBUG_MODE_ENABLED && m_debug_print_lvl >= 2) { printProgress(m_speciesName, m_molNumSpecies_old, m_SSfeSpecies); } } if (DEBUG_MODE_ENABLED && m_debug_print_lvl == 1) { printProgress(m_speciesName, m_molNumSpecies_old, m_SSfeSpecies); plogf(" --- setInitialMoles end\n"); } retn = 0; if (!abundancesOK) { retn = -1; } else if (iter > 15) { retn = 1; } return retn; }
int VCS_SOLVE::vcs_inest_TP() { int retn = 0; Cantera::clockWC tickTock; if (m_doEstimateEquil > 0) { /* * Calculate the elemental abundances */ vcs_elab(); if (vcs_elabcheck(0)) { if (DEBUG_MODE_ENABLED && m_debug_print_lvl >= 2) { plogf("%s Initial guess passed element abundances on input\n", pprefix); plogf("%s m_doEstimateEquil = 1 so will use the input mole " "numbers as estimates", pprefix); plogendl(); } return retn; } else if (DEBUG_MODE_ENABLED && m_debug_print_lvl >= 2) { plogf("%s Initial guess failed element abundances on input\n", pprefix); plogf("%s m_doEstimateEquil = 1 so will discard input " "mole numbers and find our own estimate", pprefix); plogendl(); } } /* * Malloc temporary space for usage in this routine and in * subroutines * sm[ne*ne] * ss[ne] * sa[ne] * aw[m] */ std::vector<double> sm(m_numElemConstraints*m_numElemConstraints, 0.0); std::vector<double> ss(m_numElemConstraints, 0.0); std::vector<double> sa(m_numElemConstraints, 0.0); std::vector<double> aw(m_numSpeciesTot+ m_numElemConstraints, 0.0); /* * Go get the estimate of the solution */ if (DEBUG_MODE_ENABLED && m_debug_print_lvl >= 2) { plogf("%sGo find an initial estimate for the equilibrium problem", pprefix); plogendl(); } double test = -1.0E20; vcs_inest(VCS_DATA_PTR(aw), VCS_DATA_PTR(sa), VCS_DATA_PTR(sm), VCS_DATA_PTR(ss), test); /* * Calculate the elemental abundances */ vcs_elab(); /* * If we still fail to achieve the correct elemental abundances, * try to fix the problem again by calling the main elemental abundances * fixer routine, used in the main program. This * attempts to tweak the mole numbers of the component species to * satisfy the element abundance constraints. * * Note: We won't do this unless we have to since it involves inverting * a matrix. */ bool rangeCheck = vcs_elabcheck(1); if (!vcs_elabcheck(0)) { if (DEBUG_MODE_ENABLED && m_debug_print_lvl >= 2) { plogf("%sInitial guess failed element abundances\n", pprefix); plogf("%sCall vcs_elcorr to attempt fix", pprefix); plogendl(); } vcs_elcorr(VCS_DATA_PTR(sm), VCS_DATA_PTR(aw)); rangeCheck = vcs_elabcheck(1); if (!vcs_elabcheck(0)) { plogf("%sInitial guess still fails element abundance equations\n", pprefix); plogf("%s - Inability to ever satisfy element abundance " "constraints is probable", pprefix); plogendl(); retn = -1; } else { if (DEBUG_MODE_ENABLED && m_debug_print_lvl >= 2) { if (rangeCheck) { plogf("%sInitial guess now satisfies element abundances", pprefix); plogendl(); } else { plogf("%sElement Abundances RANGE ERROR\n", pprefix); plogf("%s - Initial guess satisfies NC=%d element abundances, " "BUT not NE=%d element abundances", pprefix, m_numComponents, m_numElemConstraints); plogendl(); } } } } else { if (DEBUG_MODE_ENABLED && m_debug_print_lvl >= 2) { if (rangeCheck) { plogf("%sInitial guess satisfies element abundances", pprefix); plogendl(); } else { plogf("%sElement Abundances RANGE ERROR\n", pprefix); plogf("%s - Initial guess satisfies NC=%d element abundances, " "BUT not NE=%d element abundances", pprefix, m_numComponents, m_numElemConstraints); plogendl(); } } } if (DEBUG_MODE_ENABLED && m_debug_print_lvl >= 2) { plogf("%sTotal Dimensionless Gibbs Free Energy = %15.7E", pprefix, vcs_Total_Gibbs(VCS_DATA_PTR(m_molNumSpecies_old), VCS_DATA_PTR(m_feSpecies_new), VCS_DATA_PTR(m_tPhaseMoles_old))); plogendl(); } /* * Record time */ m_VCount->T_Time_inest += tickTock.secondsWC(); (m_VCount->T_Calls_Inest)++; return retn; }