20 bool VCS_SOLVE::vcs_popPhasePossible(
const size_t iphasePop)
const 24 "called for a phase that exists!");
30 for (
size_t k = 0; k < Vphase->
nSpecies(); k++) {
33 "VCS_SOLVE::vcs_popPhasePossible",
34 "we shouldn't be here {}: {} > 0.0", kspec,
35 m_molNumSpecies_old[kspec]);
36 size_t irxn = kspec - m_numComponents;
37 if (kspec >= m_numComponents) {
38 bool iPopPossible =
true;
44 for (
size_t j = 0; j < m_numComponents; ++j) {
46 double stoicC = m_stoichCoeffRxnMatrix(j,irxn);
48 double negChangeComp = - stoicC;
49 if (negChangeComp > 0.0) {
68 for (
size_t jrxn = 0; jrxn < m_numRxnRdc; jrxn++) {
69 bool foundJrxn =
false;
71 if (m_stoichCoeffRxnMatrix(kspec,jrxn) > 0.0) {
75 for (
size_t kcomp = 0; kcomp < m_numComponents; kcomp++) {
83 }
else if (m_stoichCoeffRxnMatrix(kspec,jrxn) < 0.0) {
87 size_t jspec = jrxn + m_numComponents;
94 for (
size_t kcomp = 0; kcomp < m_numComponents; kcomp++) {
109 int VCS_SOLVE::vcs_phasePopDeterminePossibleList()
112 "Unused. To be removed after Cantera 2.3.");
114 phasePopProblemLists_.clear();
124 std::vector< std::vector<size_t> > zeroedComponentLinkedPhasePops(m_numComponents);
127 for (
size_t j = 0; j < m_numComponents; j++) {
129 std::vector<size_t> &jList = zeroedComponentLinkedPhasePops[j];
130 size_t iph = m_phaseID[j];
131 jList.push_back(iph);
132 for (
size_t irxn = 0; irxn < m_numRxnTot; irxn++) {
133 size_t kspec = irxn + m_numComponents;
134 iph = m_phaseID[kspec];
136 int existence = Vphase->
exists();
137 if (existence < 0 && m_stoichCoeffRxnMatrix(j,irxn) > 0.0 &&
138 std::find(jList.begin(), jList.end(), iph) != jList.end()) {
139 jList.push_back(iph);
150 std::vector< std::vector<size_t> > zeroedPhaseLinkedZeroComponents(m_numPhases);
153 for (
size_t iph = 0; iph < m_numPhases; iph++) {
154 std::vector<size_t> &iphList = zeroedPhaseLinkedZeroComponents[iph];
157 if (Vphase->
exists() < 0) {
159 for (
size_t k = 0; k < nsp; k++) {
161 size_t irxn = kspec - m_numComponents;
162 for (
size_t j = 0; j < m_numComponents; j++) {
163 if (m_elType[j] ==
VCS_ELEM_TYPE_ABSPOS && m_molNumSpecies_old[j] <= 0.0 && m_stoichCoeffRxnMatrix(j,irxn) < 0.0) {
164 bool foundPos =
false;
165 for (
size_t kk = 0; kk < nsp; kk++) {
167 if (kkspec >= m_numComponents) {
168 size_t iirxn = kkspec - m_numComponents;
169 if (m_stoichCoeffRxnMatrix(j,iirxn) > 0.0) {
174 if (!foundPos && std::find(iphList.begin(), iphList.end(), j) != iphList.end()) {
175 iphList.push_back(j);
184 for (
size_t iph = 0; iph < m_numPhases; iph++) {
186 if (Vphase->
exists() < 0) {
187 std::vector<size_t> &iphList = zeroedPhaseLinkedZeroComponents[iph];
188 std::vector<size_t> popProblem(0);
189 popProblem.push_back(iph);
190 for (
size_t i = 0; i < iphList.size(); i++) {
191 size_t j = iphList[i];
192 std::vector<size_t> &jList = zeroedComponentLinkedPhasePops[j];
193 for (
size_t jjl = 0; jjl < jList.size(); jjl++) {
194 size_t jph = jList[jjl];
195 if (std::find(popProblem.begin(), popProblem.end(), jph) != popProblem.end()) {
196 popProblem.push_back(jph);
200 phasePopProblemLists_.push_back(popProblem);
206 size_t VCS_SOLVE::vcs_popPhaseID(std::vector<size_t> & phasePopPhaseIDs)
208 size_t iphasePop =
npos;
209 doublereal FephaseMax = -1.0E30;
210 doublereal Fephase = -1.0E30;
213 if (m_debug_print_lvl >= 2) {
214 plogf(
" --- vcs_popPhaseID() called\n");
215 plogf(
" --- Phase Status F_e MoleNum\n");
216 plogf(
" --------------------------------------------------------------------------\n");
218 for (
size_t iph = 0; iph < m_numPhases; iph++) {
220 int existence = Vphase->
exists();
223 if (m_debug_print_lvl >= 2) {
224 plogf(
" --- %18s %5d NA %11.3e\n",
225 Vphase->
PhaseName, existence, m_tPhaseMoles_old[iph]);
231 size_t irxn = kspec - m_numComponents;
232 if (irxn > m_deltaGRxn_old.size()) {
234 "Index out of bounds due to logic error.");
236 doublereal deltaGRxn = m_deltaGRxn_old[irxn];
237 Fephase = exp(-deltaGRxn) - 1.0;
239 strcpy(anote,
" (ready to be birthed)");
240 if (Fephase > FephaseMax) {
242 FephaseMax = Fephase;
243 strcpy(anote,
" (chosen to be birthed)");
247 strcpy(anote,
" (not stable)");
249 "VCS_SOLVE::vcs_popPhaseID",
"shouldn't be here");
252 if (m_debug_print_lvl >= 2) {
253 plogf(
" --- %18s %5d %10.3g %10.3g %s\n",
255 m_tPhaseMoles_old[iph], anote);
259 if (vcs_popPhasePossible(iph)) {
260 Fephase = vcs_phaseStabilityTest(iph);
262 if (Fephase > FephaseMax) {
264 FephaseMax = Fephase;
267 FephaseMax = std::max(FephaseMax, Fephase);
269 if (m_debug_print_lvl >= 2) {
270 plogf(
" --- %18s %5d %11.3g %11.3g\n",
272 m_tPhaseMoles_old[iph]);
275 if (m_debug_print_lvl >= 2) {
276 plogf(
" --- %18s %5d blocked %11.3g\n",
278 existence, m_tPhaseMoles_old[iph]);
284 phasePopPhaseIDs.resize(0);
285 if (iphasePop !=
npos) {
286 phasePopPhaseIDs.push_back(iphasePop);
291 if (m_debug_print_lvl >= 2) {
292 plogf(
" ---------------------------------------------------------------------\n");
297 int VCS_SOLVE::vcs_popPhaseRxnStepSizes(
const size_t iphasePop)
303 size_t irxn = kspec - m_numComponents;
304 std::vector<size_t> creationGlobalRxnNumbers;
312 "called for a phase that exists!");
313 if (m_debug_print_lvl >= 2) {
314 plogf(
" --- vcs_popPhaseRxnStepSizes() called to pop phase %s %d into existence\n",
320 for (
size_t j = 0; j < m_numComponents; ++j) {
321 if (!m_SSPhase[j] && m_molNumSpecies_old[j] > 0.0) {
322 s += pow(m_stoichCoeffRxnMatrix(j,irxn), 2) / m_molNumSpecies_old[j];
325 for (
size_t j = 0; j < m_numPhases; j++) {
326 Vphase = m_VolPhaseList[j];
328 s -= pow(m_deltaMolNumPhase(j,irxn), 2) / m_tPhaseMoles_old[j];
333 s = vcs_Hessian_diag_adj(irxn, s_old);
334 m_deltaMolNumSpecies[kspec] = -m_deltaGRxn_new[irxn] / s;
338 m_deltaMolNumSpecies[kspec] = tPhaseMoles;
342 for (
size_t j = 0; j < m_numComponents; ++j) {
343 double stoicC = m_stoichCoeffRxnMatrix(j,irxn);
345 double negChangeComp = - stoicC * m_deltaMolNumSpecies[kspec];
346 if (negChangeComp > m_molNumSpecies_old[j]) {
347 if (m_molNumSpecies_old[j] > 0.0) {
348 m_deltaMolNumSpecies[kspec] = - 0.5 * m_molNumSpecies_old[j] / stoicC;
350 m_deltaMolNumSpecies[kspec] = 0.0;
357 if (-m_deltaMolNumSpecies[kspec] > m_molNumSpecies_old[kspec]) {
358 m_deltaMolNumSpecies[kspec] = -m_molNumSpecies_old[kspec];
365 double sumFrac = 0.0;
366 for (
size_t k = 0; k < Vphase->
nSpecies(); k++) {
367 sumFrac += fracDelta[k];
369 for (
size_t k = 0; k < Vphase->
nSpecies(); k++) {
370 X_est[k] = fracDelta[k] / sumFrac;
373 doublereal deltaMolNumPhase = tPhaseMoles;
374 doublereal damp = 1.0;
375 m_deltaGRxn_tmp = m_molNumSpecies_old;
376 double* molNumSpecies_tmp = m_deltaGRxn_tmp.data();
378 for (
size_t k = 0; k < Vphase->
nSpecies(); k++) {
380 double delmol = deltaMolNumPhase * X_est[k];
381 if (kspec >= m_numComponents) {
382 irxn = kspec - m_numComponents;
383 if (irxn > m_stoichCoeffRxnMatrix.nColumns()) {
384 throw CanteraError(
"VCS_SOLVE::vcs_popPhaseRxnStepSizes",
385 "Index out of bounds due to logic error.");
387 for (
size_t j = 0; j < m_numComponents; ++j) {
388 double stoicC = m_stoichCoeffRxnMatrix(j,irxn);
390 molNumSpecies_tmp[j] += stoicC * delmol;
396 doublereal ratioComp = 0.0;
397 for (
size_t j = 0; j < m_numComponents; ++j) {
398 double deltaJ = m_molNumSpecies_old[j] - molNumSpecies_tmp[j];
399 if (molNumSpecies_tmp[j] < 0.0) {
402 double delta0 = m_molNumSpecies_old[j];
403 damp = std::min(damp, delta0 / deltaJ * 0.9);
407 size_t jph = m_phaseID[j];
408 if ((jph != iphasePop) && (!m_SSPhase[j])) {
409 double fdeltaJ = fabs(deltaJ);
410 if (m_molNumSpecies_old[j] > 0.0) {
411 ratioComp = std::max(ratioComp, fdeltaJ/ m_molNumSpecies_old[j]);
422 if (ratioComp > 1.0E-30 && ratioComp < 0.001) {
423 damp = 0.001 / ratioComp;
425 if (damp <= 1.0E-6) {
429 for (
size_t k = 0; k < Vphase->
nSpecies(); k++) {
431 if (kspec < m_numComponents) {
434 m_deltaMolNumSpecies[kspec] = deltaMolNumPhase * X_est[k] * damp;
435 if (X_est[k] > 1.0E-3) {
446 double VCS_SOLVE::vcs_phaseStabilityTest(
const size_t iph)
450 const size_t nsp = Vphase->
nSpecies();
451 int minNumberIterations = 3;
453 minNumberIterations = 1;
457 bool doSuccessiveSubstitution =
true;
458 double funcPhaseStability;
464 vector<size_t> creationGlobalRxnNumbers(nsp,
npos);
465 m_deltaGRxn_Deficient = m_deltaGRxn_old;
466 vector_fp feSpecies_Deficient = m_feSpecies_old;
475 std::vector<size_t> componentList;
476 for (
size_t k = 0; k < nsp; k++) {
478 if (kspec < m_numComponents) {
479 componentList.push_back(k);
483 double normUpdate = 0.1 *
vcs_l2norm(fracDelta_new);
484 double damp = 1.0E-2;
486 if (doSuccessiveSubstitution) {
488 if (m_debug_print_lvl >= 2) {
489 plogf(
" --- vcs_phaseStabilityTest() called\n");
490 plogf(
" --- Its X_old[%2d] FracDel_old[%2d] deltaF[%2d] FracDel_new[%2d]" 491 " normUpdate damp FuncPhaseStability\n", KP, KP, KP, KP);
492 plogf(
" --------------------------------------------------------------" 493 "--------------------------------------------------------\n");
494 }
else if (m_debug_print_lvl == 1) {
495 plogf(
" --- vcs_phaseStabilityTest() called for phase %d\n", iph);
498 for (
size_t k = 0; k < nsp; k++) {
499 if (fracDelta_new[k] < 1.0E-13) {
500 fracDelta_new[k] =1.0E-13;
503 bool converged =
false;
504 double dirProd = 0.0;
505 for (
int its = 0; its < 200 && (!converged); its++) {
506 double dampOld = damp;
507 double normUpdateOld = normUpdate;
508 fracDelta_old = fracDelta_new;
509 double dirProdOld = dirProd;
513 for (
size_t i = 0; i < componentList.size(); i++) {
514 size_t kc = componentList[i];
516 fracDelta_old[kc] = 0.0;
517 for (
size_t k = 0; k < nsp; k++) {
519 if (kspec >= m_numComponents) {
520 size_t irxn = kspec - m_numComponents;
521 fracDelta_old[kc] += m_stoichCoeffRxnMatrix(kc_spec,irxn) * fracDelta_old[k];
527 double sumFrac = 0.0;
528 for (
size_t k = 0; k < nsp; k++) {
529 sumFrac += fracDelta_old[k];
533 if (sumFrac <= 0.0) {
536 double sum_Xcomp = 0.0;
537 for (
size_t k = 0; k < nsp; k++) {
538 X_est[k] = fracDelta_old[k] / sumFrac;
540 sum_Xcomp += X_est[k];
553 for (
size_t i = 0; i < componentList.size(); i++) {
554 size_t kc = componentList[i];
557 feSpecies_Deficient[kc_spec] = m_feSpecies_old[kc_spec]
558 + log(m_actCoeffSpecies_new[kc_spec] * X_est[kc]);
560 feSpecies_Deficient[kc_spec] = m_feSpecies_old[kc_spec]
565 for (
size_t i = 0; i < componentList.size(); i++) {
567 for (
size_t k = 0; k < Vphase->
nSpecies(); k++) {
569 if (kspec >= m_numComponents) {
570 size_t irxn = kspec - m_numComponents;
572 m_deltaGRxn_Deficient[irxn] = m_deltaGRxn_old[irxn];
574 if (m_stoichCoeffRxnMatrix(kc_spec,irxn) != 0.0) {
575 m_deltaGRxn_Deficient[irxn] +=
576 m_stoichCoeffRxnMatrix(kc_spec,irxn) * (feSpecies_Deficient[kc_spec]- m_feSpecies_old[kc_spec]);
584 funcPhaseStability = sum_Xcomp - 1.0;
585 for (
size_t k = 0; k < nsp; k++) {
587 if (kspec >= m_numComponents) {
588 size_t irxn = kspec - m_numComponents;
589 double deltaGRxn =
clip(m_deltaGRxn_Deficient[irxn], -50.0, 50.0);
590 E_phi[k] = std::exp(-deltaGRxn) / m_actCoeffSpecies_new[kspec];
592 funcPhaseStability += E_phi[k];
599 for (
size_t k = 0; k < nsp; k++) {
601 double b = E_phi[k] / sum * (1.0 - sum_Xcomp);
602 if (kspec >= m_numComponents) {
603 fracDelta_raw[k] = b;
609 for (
size_t i = 0; i < componentList.size(); i++) {
610 size_t kc = componentList[i];
612 fracDelta_raw[kc] = 0.0;
613 for (
size_t k = 0; k < nsp; k++) {
615 if (kspec >= m_numComponents) {
616 size_t irxn = kspec - m_numComponents;
617 fracDelta_raw[kc] += m_stoichCoeffRxnMatrix(kc_spec,irxn) * fracDelta_raw[k];
623 doublereal sumADel = 0.0;
624 for (
size_t k = 0; k < nsp; k++) {
625 delFrac[k] = fracDelta_raw[k] - fracDelta_old[k];
626 sumADel += fabs(delFrac[k]);
631 for (
size_t k = 0; k < nsp; k++) {
632 dirProd += fracDelta_old[k] * delFrac[k];
634 bool crossedSign =
false;
635 if (dirProd * dirProdOld < 0.0) {
640 if (dampOld < 0.25) {
641 damp = 2.0 * dampOld;
644 if (normUpdate *1.5 > normUpdateOld) {
645 damp = 0.5 * dampOld;
646 }
else if (normUpdate *2.0 > normUpdateOld) {
647 damp = 0.8 * dampOld;
650 if (normUpdate > normUpdateOld * 2.0) {
651 damp = 0.6 * dampOld;
652 }
else if (normUpdate > normUpdateOld * 1.2) {
653 damp = 0.9 * dampOld;
657 for (
size_t k = 0; k < nsp; k++) {
658 if (fabs(damp * delFrac[k]) > 0.3*fabs(fracDelta_old[k])) {
659 damp = std::max(0.3*fabs(fracDelta_old[k]) / fabs(delFrac[k]),
660 1.0E-8/fabs(delFrac[k]));
662 if (delFrac[k] < 0.0 && 2.0 * damp * (-delFrac[k]) > fracDelta_old[k]) {
663 damp = fracDelta_old[k] / (2.0 * -delFrac[k]);
665 if (delFrac[k] > 0.0 && 2.0 * damp * delFrac[k] > fracDelta_old[k]) {
666 damp = fracDelta_old[k] / (2.0 * delFrac[k]);
669 damp = std::max(damp, 0.000001);
670 for (
size_t k = 0; k < nsp; k++) {
671 fracDelta_new[k] = fracDelta_old[k] + damp * delFrac[k];
674 if (m_debug_print_lvl >= 2) {
675 plogf(
" --- %3d %12g %12g %12g %12g %12g %12g %12g\n", its, X_est[KP], fracDelta_old[KP],
676 delFrac[KP], fracDelta_new[KP], normUpdate, damp, funcPhaseStability);
679 if (normUpdate < 1.0E-5 * damp) {
681 if (its < minNumberIterations) {
696 throw CanteraError(
"VCS_SOLVE::vcs_phaseStabilityTest",
"not done yet");
698 if (m_debug_print_lvl >= 2) {
699 plogf(
" ------------------------------------------------------------" 700 "-------------------------------------------------------------\n");
701 }
else if (m_debug_print_lvl == 1) {
702 if (funcPhaseStability > 0.0) {
703 plogf(
" --- phase %d with func = %g is to be born\n", iph, funcPhaseStability);
705 plogf(
" --- phase %d with func = %g stays dead\n", iph, funcPhaseStability);
708 return funcPhaseStability;
void setCreationMoleNumbers(const double *const n_k, const std::vector< size_t > &creationGlobalRxnNumbers)
Sets the creationMoleNum's within the phase object.
bool m_singleSpecies
If true, this phase consists of a single species.
void setMoleFractionsState(const double molNum, const double *const moleFracVec, const int vcsStateStatus)
Set the moles and/or mole fractions within the phase.
#define VCS_SPECIES_MINOR
Species is a major species.
const size_t npos
index returned by functions to indicate "no position"
#define VCS_DELETE_ELEMENTABS_CUTOFF
Cutoff moles below which a phase or species which comprises the bulk of an element's total concentrat...
T clip(const T &value, const T &lower, const T &upper)
Clip value such that lower <= value <= upper.
void warn_deprecated(const std::string &method, const std::string &extra)
Print a warning indicating that method is deprecated.
size_t spGlobalIndexVCS(const size_t spIndex) const
Return the Global VCS index of the kth species in the phase.
const vector_fp & creationMoleNumbers(std::vector< size_t > &creationGlobalRxnNumbers) const
Return a const reference to the creationMoleNumbers stored in the object.
std::string PhaseName
String name for the phase.
#define VCS_STATECALC_PHASESTABILITY
State Calculation based on tentative mole numbers for a phase which is currently zeroed, but is being evaluated for whether it should pop back into existence.
Header file for the internal object that holds the vcs equilibrium problem (see Class VCS_SOLVE and E...
Header for the object representing each phase within vcs.
#define VCS_ELEM_TYPE_ABSPOS
Normal element constraint consisting of positive coefficients for the formula matrix.
#define VCS_DELETE_MINORSPECIES_CUTOFF
Cutoff relative mole number value, below which species are deleted from the equilibrium problem...
#define VCS_DELETE_PHASE_CUTOFF
Cutoff relative moles below which a phase is deleted from the equilibrium problem.
size_t nSpecies() const
Return the number of species in the phase.
Base class for exceptions thrown by Cantera classes.
void sendToVCS_ActCoeff(const int stateCalc, double *const AC)
Fill in an activity coefficients vector within a VCS_SOLVE object.
#define VCS_SPECIES_MAJOR
Species is a major species.
Phase information and Phase calculations for vcs.
#define AssertThrowMsg(expr, procedure,...)
Assertion must be true or an error is thrown.
double vcs_l2norm(const vector_fp &vec)
determine the l2 norm of a vector of doubles
#define VCS_STATECALC_OLD
State Calculation based on the old or base mole numbers.
int exists() const
int indicating whether the phase exists or not
std::vector< double > vector_fp
Turn on the use of stl vectors for the basic array type within cantera Vector of doubles.
Contains declarations for string manipulation functions within Cantera.
#define plogf
define this Cantera function to replace printf
#define VCS_SPECIES_COMPONENT
Species is a component which can be nonzero.
Namespace for the Cantera kernel.
Definitions for the classes that are thrown when Cantera experiences an error condition (also contain...