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 size_t VCS_SOLVE::vcs_popPhaseID(std::vector<size_t> & phasePopPhaseIDs)
111 size_t iphasePop =
npos;
112 doublereal FephaseMax = -1.0E30;
113 doublereal Fephase = -1.0E30;
116 if (m_debug_print_lvl >= 2) {
117 plogf(
" --- vcs_popPhaseID() called\n");
118 plogf(
" --- Phase Status F_e MoleNum\n");
119 plogf(
" --------------------------------------------------------------------------\n");
121 for (
size_t iph = 0; iph < m_numPhases; iph++) {
123 int existence = Vphase->
exists();
126 if (m_debug_print_lvl >= 2) {
127 plogf(
" --- %18s %5d NA %11.3e\n",
128 Vphase->
PhaseName, existence, m_tPhaseMoles_old[iph]);
134 size_t irxn = kspec - m_numComponents;
135 if (irxn > m_deltaGRxn_old.size()) {
137 "Index out of bounds due to logic error.");
139 doublereal deltaGRxn = m_deltaGRxn_old[irxn];
140 Fephase = exp(-deltaGRxn) - 1.0;
142 strcpy(anote,
" (ready to be birthed)");
143 if (Fephase > FephaseMax) {
145 FephaseMax = Fephase;
146 strcpy(anote,
" (chosen to be birthed)");
150 strcpy(anote,
" (not stable)");
152 "VCS_SOLVE::vcs_popPhaseID",
"shouldn't be here");
155 if (m_debug_print_lvl >= 2) {
156 plogf(
" --- %18s %5d %10.3g %10.3g %s\n",
158 m_tPhaseMoles_old[iph], anote);
162 if (vcs_popPhasePossible(iph)) {
163 Fephase = vcs_phaseStabilityTest(iph);
165 if (Fephase > FephaseMax) {
167 FephaseMax = Fephase;
170 FephaseMax = std::max(FephaseMax, Fephase);
172 if (m_debug_print_lvl >= 2) {
173 plogf(
" --- %18s %5d %11.3g %11.3g\n",
175 m_tPhaseMoles_old[iph]);
178 if (m_debug_print_lvl >= 2) {
179 plogf(
" --- %18s %5d blocked %11.3g\n",
181 existence, m_tPhaseMoles_old[iph]);
187 phasePopPhaseIDs.resize(0);
188 if (iphasePop !=
npos) {
189 phasePopPhaseIDs.push_back(iphasePop);
194 if (m_debug_print_lvl >= 2) {
195 plogf(
" ---------------------------------------------------------------------\n");
200 int VCS_SOLVE::vcs_popPhaseRxnStepSizes(
const size_t iphasePop)
206 size_t irxn = kspec - m_numComponents;
207 std::vector<size_t> creationGlobalRxnNumbers;
215 "called for a phase that exists!");
216 if (m_debug_print_lvl >= 2) {
217 plogf(
" --- vcs_popPhaseRxnStepSizes() called to pop phase %s %d into existence\n",
223 for (
size_t j = 0; j < m_numComponents; ++j) {
224 if (!m_SSPhase[j] && m_molNumSpecies_old[j] > 0.0) {
225 s += pow(m_stoichCoeffRxnMatrix(j,irxn), 2) / m_molNumSpecies_old[j];
228 for (
size_t j = 0; j < m_numPhases; j++) {
229 Vphase = m_VolPhaseList[j].get();
231 s -= pow(m_deltaMolNumPhase(j,irxn), 2) / m_tPhaseMoles_old[j];
236 s = vcs_Hessian_diag_adj(irxn, s_old);
237 m_deltaMolNumSpecies[kspec] = -m_deltaGRxn_new[irxn] / s;
241 m_deltaMolNumSpecies[kspec] = tPhaseMoles;
245 for (
size_t j = 0; j < m_numComponents; ++j) {
246 double stoicC = m_stoichCoeffRxnMatrix(j,irxn);
248 double negChangeComp = - stoicC * m_deltaMolNumSpecies[kspec];
249 if (negChangeComp > m_molNumSpecies_old[j]) {
250 if (m_molNumSpecies_old[j] > 0.0) {
251 m_deltaMolNumSpecies[kspec] = - 0.5 * m_molNumSpecies_old[j] / stoicC;
253 m_deltaMolNumSpecies[kspec] = 0.0;
260 if (-m_deltaMolNumSpecies[kspec] > m_molNumSpecies_old[kspec]) {
261 m_deltaMolNumSpecies[kspec] = -m_molNumSpecies_old[kspec];
268 double sumFrac = 0.0;
269 for (
size_t k = 0; k < Vphase->
nSpecies(); k++) {
270 sumFrac += fracDelta[k];
272 for (
size_t k = 0; k < Vphase->
nSpecies(); k++) {
273 X_est[k] = fracDelta[k] / sumFrac;
276 doublereal deltaMolNumPhase = tPhaseMoles;
277 doublereal damp = 1.0;
278 m_deltaGRxn_tmp = m_molNumSpecies_old;
279 double* molNumSpecies_tmp = m_deltaGRxn_tmp.data();
281 for (
size_t k = 0; k < Vphase->
nSpecies(); k++) {
283 double delmol = deltaMolNumPhase * X_est[k];
284 if (kspec >= m_numComponents) {
285 irxn = kspec - m_numComponents;
286 if (irxn > m_stoichCoeffRxnMatrix.nColumns()) {
287 throw CanteraError(
"VCS_SOLVE::vcs_popPhaseRxnStepSizes",
288 "Index out of bounds due to logic error.");
290 for (
size_t j = 0; j < m_numComponents; ++j) {
291 double stoicC = m_stoichCoeffRxnMatrix(j,irxn);
293 molNumSpecies_tmp[j] += stoicC * delmol;
299 doublereal ratioComp = 0.0;
300 for (
size_t j = 0; j < m_numComponents; ++j) {
301 double deltaJ = m_molNumSpecies_old[j] - molNumSpecies_tmp[j];
302 if (molNumSpecies_tmp[j] < 0.0) {
305 double delta0 = m_molNumSpecies_old[j];
306 damp = std::min(damp, delta0 / deltaJ * 0.9);
310 size_t jph = m_phaseID[j];
311 if ((jph != iphasePop) && (!m_SSPhase[j])) {
312 double fdeltaJ = fabs(deltaJ);
313 if (m_molNumSpecies_old[j] > 0.0) {
314 ratioComp = std::max(ratioComp, fdeltaJ/ m_molNumSpecies_old[j]);
325 if (ratioComp > 1.0E-30 && ratioComp < 0.001) {
326 damp = 0.001 / ratioComp;
328 if (damp <= 1.0E-6) {
332 for (
size_t k = 0; k < Vphase->
nSpecies(); k++) {
334 if (kspec < m_numComponents) {
337 m_deltaMolNumSpecies[kspec] = deltaMolNumPhase * X_est[k] * damp;
338 if (X_est[k] > 1.0E-3) {
349 double VCS_SOLVE::vcs_phaseStabilityTest(
const size_t iph)
353 const size_t nsp = Vphase->
nSpecies();
354 int minNumberIterations = 3;
356 minNumberIterations = 1;
360 bool doSuccessiveSubstitution =
true;
361 double funcPhaseStability;
367 vector<size_t> creationGlobalRxnNumbers(nsp,
npos);
368 m_deltaGRxn_Deficient = m_deltaGRxn_old;
369 vector_fp feSpecies_Deficient = m_feSpecies_old;
378 std::vector<size_t> componentList;
379 for (
size_t k = 0; k < nsp; k++) {
381 if (kspec < m_numComponents) {
382 componentList.push_back(k);
386 double normUpdate = 0.1 *
vcs_l2norm(fracDelta_new);
387 double damp = 1.0E-2;
389 if (doSuccessiveSubstitution) {
391 if (m_debug_print_lvl >= 2) {
392 plogf(
" --- vcs_phaseStabilityTest() called\n");
393 plogf(
" --- Its X_old[%2d] FracDel_old[%2d] deltaF[%2d] FracDel_new[%2d]"
394 " normUpdate damp FuncPhaseStability\n", KP, KP, KP, KP);
395 plogf(
" --------------------------------------------------------------"
396 "--------------------------------------------------------\n");
397 }
else if (m_debug_print_lvl == 1) {
398 plogf(
" --- vcs_phaseStabilityTest() called for phase %d\n", iph);
401 for (
size_t k = 0; k < nsp; k++) {
402 if (fracDelta_new[k] < 1.0E-13) {
403 fracDelta_new[k] =1.0E-13;
406 bool converged =
false;
407 double dirProd = 0.0;
408 for (
int its = 0; its < 200 && (!converged); its++) {
409 double dampOld = damp;
410 double normUpdateOld = normUpdate;
411 fracDelta_old = fracDelta_new;
412 double dirProdOld = dirProd;
416 for (
size_t i = 0; i < componentList.size(); i++) {
417 size_t kc = componentList[i];
419 fracDelta_old[kc] = 0.0;
420 for (
size_t k = 0; k < nsp; k++) {
422 if (kspec >= m_numComponents) {
423 size_t irxn = kspec - m_numComponents;
424 fracDelta_old[kc] += m_stoichCoeffRxnMatrix(kc_spec,irxn) * fracDelta_old[k];
430 double sumFrac = 0.0;
431 for (
size_t k = 0; k < nsp; k++) {
432 sumFrac += fracDelta_old[k];
436 if (sumFrac <= 0.0) {
439 double sum_Xcomp = 0.0;
440 for (
size_t k = 0; k < nsp; k++) {
441 X_est[k] = fracDelta_old[k] / sumFrac;
443 sum_Xcomp += X_est[k];
456 for (
size_t i = 0; i < componentList.size(); i++) {
457 size_t kc = componentList[i];
460 feSpecies_Deficient[kc_spec] = m_feSpecies_old[kc_spec]
461 + log(m_actCoeffSpecies_new[kc_spec] * X_est[kc]);
463 feSpecies_Deficient[kc_spec] = m_feSpecies_old[kc_spec]
468 for (
size_t i = 0; i < componentList.size(); i++) {
470 for (
size_t k = 0; k < Vphase->
nSpecies(); k++) {
472 if (kspec >= m_numComponents) {
473 size_t irxn = kspec - m_numComponents;
475 m_deltaGRxn_Deficient[irxn] = m_deltaGRxn_old[irxn];
477 if (m_stoichCoeffRxnMatrix(kc_spec,irxn) != 0.0) {
478 m_deltaGRxn_Deficient[irxn] +=
479 m_stoichCoeffRxnMatrix(kc_spec,irxn) * (feSpecies_Deficient[kc_spec]- m_feSpecies_old[kc_spec]);
487 funcPhaseStability = sum_Xcomp - 1.0;
488 for (
size_t k = 0; k < nsp; k++) {
490 if (kspec >= m_numComponents) {
491 size_t irxn = kspec - m_numComponents;
492 double deltaGRxn =
clip(m_deltaGRxn_Deficient[irxn], -50.0, 50.0);
493 E_phi[k] = std::exp(-deltaGRxn) / m_actCoeffSpecies_new[kspec];
495 funcPhaseStability += E_phi[k];
502 for (
size_t k = 0; k < nsp; k++) {
504 double b = E_phi[k] / sum * (1.0 - sum_Xcomp);
505 if (kspec >= m_numComponents) {
506 fracDelta_raw[k] = b;
512 for (
size_t i = 0; i < componentList.size(); i++) {
513 size_t kc = componentList[i];
515 fracDelta_raw[kc] = 0.0;
516 for (
size_t k = 0; k < nsp; k++) {
518 if (kspec >= m_numComponents) {
519 size_t irxn = kspec - m_numComponents;
520 fracDelta_raw[kc] += m_stoichCoeffRxnMatrix(kc_spec,irxn) * fracDelta_raw[k];
526 doublereal sumADel = 0.0;
527 for (
size_t k = 0; k < nsp; k++) {
528 delFrac[k] = fracDelta_raw[k] - fracDelta_old[k];
529 sumADel += fabs(delFrac[k]);
534 for (
size_t k = 0; k < nsp; k++) {
535 dirProd += fracDelta_old[k] * delFrac[k];
537 bool crossedSign =
false;
538 if (dirProd * dirProdOld < 0.0) {
543 if (dampOld < 0.25) {
544 damp = 2.0 * dampOld;
547 if (normUpdate *1.5 > normUpdateOld) {
548 damp = 0.5 * dampOld;
549 }
else if (normUpdate *2.0 > normUpdateOld) {
550 damp = 0.8 * dampOld;
553 if (normUpdate > normUpdateOld * 2.0) {
554 damp = 0.6 * dampOld;
555 }
else if (normUpdate > normUpdateOld * 1.2) {
556 damp = 0.9 * dampOld;
560 for (
size_t k = 0; k < nsp; k++) {
561 if (fabs(damp * delFrac[k]) > 0.3*fabs(fracDelta_old[k])) {
562 damp = std::max(0.3*fabs(fracDelta_old[k]) / fabs(delFrac[k]),
563 1.0E-8/fabs(delFrac[k]));
565 if (delFrac[k] < 0.0 && 2.0 * damp * (-delFrac[k]) > fracDelta_old[k]) {
566 damp = fracDelta_old[k] / (2.0 * -delFrac[k]);
568 if (delFrac[k] > 0.0 && 2.0 * damp * delFrac[k] > fracDelta_old[k]) {
569 damp = fracDelta_old[k] / (2.0 * delFrac[k]);
572 damp = std::max(damp, 0.000001);
573 for (
size_t k = 0; k < nsp; k++) {
574 fracDelta_new[k] = fracDelta_old[k] + damp * delFrac[k];
577 if (m_debug_print_lvl >= 2) {
578 plogf(
" --- %3d %12g %12g %12g %12g %12g %12g %12g\n", its, X_est[KP], fracDelta_old[KP],
579 delFrac[KP], fracDelta_new[KP], normUpdate, damp, funcPhaseStability);
582 if (normUpdate < 1.0E-5 * damp) {
584 if (its < minNumberIterations) {
599 throw CanteraError(
"VCS_SOLVE::vcs_phaseStabilityTest",
"not done yet");
601 if (m_debug_print_lvl >= 2) {
602 plogf(
" ------------------------------------------------------------"
603 "-------------------------------------------------------------\n");
604 }
else if (m_debug_print_lvl == 1) {
605 if (funcPhaseStability > 0.0) {
606 plogf(
" --- phase %d with func = %g is to be born\n", iph, funcPhaseStability);
608 plogf(
" --- phase %d with func = %g stays dead\n", iph, funcPhaseStability);
611 return funcPhaseStability;
Base class for exceptions thrown by Cantera classes.
Phase information and Phase calculations for vcs.
size_t nSpecies() const
Return the number of species in the phase.
void setMoleFractionsState(const double molNum, const double *const moleFracVec, const int vcsStateStatus)
Set the moles and/or mole fractions within the phase.
bool m_singleSpecies
If true, this phase consists of a single species.
int exists() const
int indicating whether the phase exists or not
size_t spGlobalIndexVCS(const size_t spIndex) const
Return the Global VCS index of the kth species in the phase.
std::string PhaseName
String name for the phase.
void setCreationMoleNumbers(const double *const n_k, const std::vector< size_t > &creationGlobalRxnNumbers)
Sets the creationMoleNum's within the phase object.
void sendToVCS_ActCoeff(const int stateCalc, double *const AC)
Fill in an activity coefficients vector within a VCS_SOLVE object.
const vector_fp & creationMoleNumbers(std::vector< size_t > &creationGlobalRxnNumbers) const
Return a const reference to the creationMoleNumbers stored in the object.
Definitions for the classes that are thrown when Cantera experiences an error condition (also contain...
#define AssertThrowMsg(expr, procedure,...)
Assertion must be true or an error is thrown.
const size_t npos
index returned by functions to indicate "no position"
std::vector< double > vector_fp
Turn on the use of stl vectors for the basic array type within cantera Vector of doubles.
Namespace for the Cantera kernel.
double vcs_l2norm(const vector_fp &vec)
determine the l2 norm of a vector of doubles
Contains declarations for string manipulation functions within Cantera.
Header for the object representing each phase within vcs.
#define VCS_STATECALC_OLD
State Calculation based on the old or base mole numbers.
#define VCS_DELETE_MINORSPECIES_CUTOFF
Cutoff relative mole number value, below which species are deleted from the equilibrium problem.
#define VCS_SPECIES_COMPONENT
Species is a component which can be nonzero.
#define VCS_SPECIES_MAJOR
Species is a major species.
#define VCS_ELEM_TYPE_ABSPOS
Normal element constraint consisting of positive coefficients for the formula matrix.
#define VCS_DELETE_PHASE_CUTOFF
Cutoff relative moles below which a phase is deleted from the equilibrium problem.
#define VCS_SPECIES_MINOR
Species is a major species.
#define VCS_DELETE_ELEMENTABS_CUTOFF
Cutoff moles below which a phase or species which comprises the bulk of an element's total concentrat...
#define VCS_STATECALC_PHASESTABILITY
State Calculation based on tentative mole numbers for a phase which is currently zeroed,...
#define plogf
define this Cantera function to replace printf
Header file for the internal object that holds the vcs equilibrium problem (see Class VCS_SOLVE and E...