19 int Cantera::ChemEquil_print_lvl = 0;
26 string flag = string(xy);
29 }
else if (flag ==
"TV") {
31 }
else if (flag ==
"HP") {
33 }
else if (flag ==
"UV") {
35 }
else if (flag ==
"SP") {
37 }
else if (flag ==
"SV") {
39 }
else if (flag ==
"UP") {
42 throw CanteraError(
"_equilflag",
"unknown property pair "+flag);
47 ChemEquil::ChemEquil() : m_skip(
npos), m_elementTotalSum(1.0),
49 m_elemFracCutoff(1.0E-100),
55 m_elementTotalSum(1.0),
57 m_elemFracCutoff(1.0E-100),
63 ChemEquil::~ChemEquil()
80 m_elementmolefracs.resize(
m_mm);
82 m_jwork1.resize(
m_mm+2);
83 m_jwork2.resize(
m_mm+2);
84 m_startSoln.resize(
m_mm+1);
89 m_orderVectorElements.resize(
m_mm);
91 for (
size_t m = 0; m <
m_mm; m++) {
92 m_orderVectorElements[m] = m;
94 m_orderVectorSpecies.resize(m_kk);
95 for (
size_t k = 0; k <
m_kk; k++) {
96 m_orderVectorSpecies[k] = k;
102 for (
size_t m = 0; m <
m_mm; m++) {
103 for (
size_t k = 0; k <
m_kk; k++) {
114 if (mneg !=
npos && mneg != m)
116 "negative atom numbers allowed for only one element");
126 +
" atoms of element "
128 ", but this element is not an electron.\n"));
135 for (
size_t k = 0; k <
m_kk; k++) {
136 for (
size_t m = 0; m <
m_mm; m++) {
137 m_comp[k*m_mm + m] = s.
nAtoms(k,m);
143 const vector_fp& lambda_RT, doublereal t)
146 fill(m_mu_RT.begin(), m_mu_RT.end(), 0.0);
147 for (
size_t k = 0; k <
m_kk; k++)
148 for (
size_t m = 0; m <
m_mm; m++) {
149 m_mu_RT[k] += lambda_RT[m]*
nAtoms(k,m);
172 for (
size_t m = 0; m <
m_mm; m++) {
173 m_elementmolefracs[m] = 0.0;
174 for (
size_t k = 0; k <
m_kk; k++) {
182 sum += m_elementmolefracs[m];
185 m_elementTotalSum = sum;
187 for (
size_t m = 0; m <
m_mm; m++) {
188 m_elementmolefracs[m] /= sum;
201 e.setInitialMixMoles(loglevel-1);
206 m_component[m] = e.componentIndex(m);
215 if (DEBUG_MODE_ENABLED && ChemEquil_print_lvl > 0) {
216 writelog(
"setInitialMoles: Estimated Mole Fractions\n");
219 for (
size_t k = 0; k <
m_kk; k++) {
222 writelogf(
" %-12s % -10.5g\n", nnn.c_str(), mf);
224 writelog(
" Element_Name ElementGoal ElementMF\n");
225 for (
size_t m = 0; m <
m_mm; m++) {
228 nnn.c_str(), elMoleGoal[m], m_elementmolefracs[m]);
248 for (
size_t n = 0; n < s.
nSpecies(); n++) {
249 xMF_est[n] = std::max(xMF_est[n], 1e-20);
257 int usedZeroedSpecies = 0;
260 &mp, m_orderVectorSpecies,
261 m_orderVectorElements, formRxnMatrix);
264 size_t k = m_orderVectorSpecies[m];
266 xMF_est[k] = std::max(xMF_est[k], 1e-8);
272 m_orderVectorSpecies, m_orderVectorElements);
276 scale(mu_RT.begin(), mu_RT.end(), mu_RT.begin(), rrt);
278 if (DEBUG_MODE_ENABLED && ChemEquil_print_lvl > 0) {
280 int isp =
static_cast<int>(m_component[m]);
282 writelogf(
"isp = %d, %s\n", isp, nnn.c_str());
289 for (
size_t n = 0; n < s.
nSpecies(); n++) {
292 n, nnn.c_str(), xMF_est[n], mu_RT[n]);
298 aa(m,n) =
nAtoms(m_component[m], m_orderVectorElements[n]);
300 b[m] = mu_RT[m_component[m]];
308 lambda_RT[m_orderVectorElements[m]] = b[m];
310 for (
size_t m = m_nComponents; m <
m_mm; m++) {
311 lambda_RT[m_orderVectorElements[m]] = 0.0;
314 if (DEBUG_MODE_ENABLED && ChemEquil_print_lvl > 0) {
315 writelog(
" id CompSpecies ChemPot EstChemPot Diff\n");
317 size_t isp = m_component[m];
320 for (
size_t n = 0; n <
m_mm; n++) {
321 tmp +=
nAtoms(isp, n) * lambda_RT[n];
323 writelogf(
"%3d %16s %10.5g %10.5g %10.5g\n",
324 m, sname.c_str(), mu_RT[isp], tmp, tmp - mu_RT[isp]);
328 for (
size_t m = 0; m <
m_mm; m++) {
330 writelogf(
" %3d %6s %10.5g\n", m, ename.c_str(), lambda_RT[m]);
337 bool useThermoPhaseElementPotentials,
int loglevel)
342 copy(m_elementmolefracs.begin(), m_elementmolefracs.end(),
343 elMolesGoal.begin());
344 return equilibrate(s, XY, elMolesGoal, useThermoPhaseElementPotentials,
350 bool useThermoPhaseElementPotentials,
353 doublereal xval, yval, tmp;
356 bool tempFixed =
true;
367 "Input ThermoPhase is incompatible with initialization");
375 m_p1.reset(
new TemperatureCalculator<thermo_t>);
376 m_p2.reset(
new PressureCalculator<thermo_t>);
381 m_p1.reset(
new EnthalpyCalculator<thermo_t>);
382 m_p2.reset(
new PressureCalculator<thermo_t>);
387 m_p1.reset(
new EntropyCalculator<thermo_t>);
388 m_p2.reset(
new PressureCalculator<thermo_t>);
393 m_p1.reset(
new EntropyCalculator<thermo_t>);
394 m_p2.reset(
new DensityCalculator<thermo_t>);
398 m_p1.reset(
new TemperatureCalculator<thermo_t>);
399 m_p2.reset(
new DensityCalculator<thermo_t>);
404 m_p1.reset(
new IntEnergyCalculator<thermo_t>);
405 m_p2.reset(
new DensityCalculator<thermo_t>);
408 throw CanteraError(
"equilibrate",
"illegal property pair.");
415 throw CanteraError(
"ChemEquil",
"Specified temperature ("
427 xval = m_p1->value(s);
428 yval = m_p2->value(s);
431 size_t nvar = mm + 1;
446 m = m_orderVectorElements[im];
447 if (elMolesGoal[m] > tmp) {
449 tmp = elMolesGoal[m];
454 "Element Abundance Vector is zeroed");
462 for (
size_t k = 0; k <
m_kk; k++) {
473 doublereal tmaxPhase = s.
maxTemp();
474 doublereal tminPhase = s.
minTemp();
477 doublereal tmin = std::max(s.
temperature(), tminPhase);
478 if (tmin > tmaxPhase) {
479 tmin = tmaxPhase - 20;
481 doublereal tmax = std::min(tmin + 10., tmaxPhase);
482 if (tmax < tminPhase) {
483 tmax = tminPhase + 20;
486 doublereal slope, phigh, plow, pval, dt;
495 phigh = m_p1->value(s);
499 plow = m_p1->value(s);
502 doublereal t0 = 0.5*(tmin + tmax);
506 for (
int it = 0; it < 10; it++) {
510 pval = m_p1->value(s);
526 slope = (phigh - plow)/(tmax - tmin);
527 dt = (xval - pval)/slope;
530 if (fabs(dt) < 50.0) {
533 dt =
clip(dt, -200.0, 200.0);
534 if ((t0 + dt) < tminPhase) {
535 dt = 0.5*((t0) + tminPhase) - t0;
537 if ((t0 + dt) > tmaxPhase) {
538 dt = 0.5*((t0) + tmaxPhase) - t0;
542 if (t0 <= tminPhase || t0 >= tmaxPhase || t0 < 100.0) {
543 throw CanteraError(
"ChemEquil::equilibrate",
"T out of bounds");
557 if (useThermoPhaseElementPotentials) {
564 for (m = 0; m <
m_mm; m++) {
612 for (m = 0; m < mm; m++) {
623 above[mm] = log(s.
maxTemp() + 25.0);
624 below[mm] = log(s.
minTemp() - 25.0);
631 doublereal fctr = 1.0, newval;
637 f = 0.5*
dot(res_trial.begin(), res_trial.end(), res_trial.begin());
638 doublereal xx, yy, deltax, deltay;
641 deltax = (xx - xval)/xval;
642 deltay = (yy - yval)/yval;
643 bool passThis =
true;
644 for (m = 0; m < nvar; m++) {
667 if (fabs(res_trial[m]) > tval) {
675 for (m = 0; m <
m_mm; m++) {
680 adjustEloc(s, elMolesGoal);
699 f = 0.5*
dot(res_trial.begin(), res_trial.end(), res_trial.begin());
702 equilJacobian(s, x, elMolesGoal, jac, xval, yval);
704 if (DEBUG_MODE_ENABLED && ChemEquil_print_lvl > 0) {
705 writelogf(
"Jacobian matrix %d:\n", iter);
706 for (m = 0; m <=
m_mm; m++) {
708 for (
size_t n = 0; n <=
m_mm; n++) {
715 sprintf(xName,
"x_%-10s", nnn.c_str());
717 sprintf(xName,
"x_XX");
720 sprintf(xName,
"x_ELOC");
723 sprintf(xName,
"x_YY");
726 writelogf(
" = - (%10.5g)\n", res_trial[m]);
730 copy(x.begin(), x.end(), oldx.begin());
732 scale(res_trial.begin(), res_trial.end(), res_trial.begin(), -1.0);
744 "Jacobian is singular. \nTry adding more species, "
745 "changing the elemental composition slightly, \nor removing "
752 for (m = 0; m < nvar; m++) {
753 newval = x[m] + res_trial[m];
754 if (newval > above[m]) {
756 std::min(fctr,0.8*(above[m] - x[m])/(newval - x[m])));
757 }
else if (newval < below[m]) {
758 if (m <
m_mm && (m != m_skip)) {
760 if (x[m] < below[m] + 50.) {
761 res_trial[m] = below[m] - x[m];
764 fctr = std::min(fctr, 0.8*(x[m] - below[m])/(x[m] - newval));
769 if (fabs(res_trial[mm]) > 0.2) {
770 fctr = std::min(fctr, 0.2/fabs(res_trial[mm]));
774 if (fctr != 1.0 && DEBUG_MODE_ENABLED && ChemEquil_print_lvl > 0) {
775 writelogf(
"WARNING Soln Damping because of bounds: %g\n", fctr);
779 scale(res_trial.begin(), res_trial.end(), res_trial.begin(), fctr);
781 if (!
dampStep(s, oldx, oldf, grad, res_trial,
782 x, f, elMolesGoal , xval, yval)) {
787 "Cannot find an acceptable Newton damping coefficient.");
804 double& f,
vector_fp& elmols,
double xval,
double yval)
812 for (
size_t m = 0; m <
m_mm; m++) {
814 if (step[m] > 1.25) {
815 damp = std::min(damp, 1.25 /step[m]);
817 if (step[m] < -1.25) {
818 damp = std::min(damp, -1.25 / step[m]);
821 if (step[m] > 0.75) {
822 damp = std::min(damp, 0.75 /step[m]);
824 if (step[m] < -0.75) {
825 damp = std::min(damp, -0.75 / step[m]);
833 for (
size_t m = 0; m < x.size(); m++) {
834 x[m] = oldx[m] + damp * step[m];
836 if (DEBUG_MODE_ENABLED && ChemEquil_print_lvl > 0) {
837 writelogf(
"Solution Unknowns: damp = %g\n", damp);
839 for (
size_t m = 0; m <
m_mm; m++) {
840 writelogf(
" % -10.5g % -10.5g % -10.5g\n", x[m], oldx[m], step[m]);
848 doublereal xval, doublereal yval,
int loglevel)
851 doublereal temp = exp(x[
m_mm]);
856 for (
size_t n = 0; n <
m_mm; n++) {
857 size_t m = m_orderVectorElements[n];
860 resid[m] = x[m] + 1000.0;
869 if (elmFracGoal[m] < 1.0E-10 || elmFrac[m] < 1.0E-10 || m ==
m_eloc) {
870 resid[m] = elmFracGoal[m] - elmFrac[m];
872 resid[m] = log((1.0 + elmFracGoal[m]) / (1.0 + elmFrac[m]));
877 if (DEBUG_MODE_ENABLED && ChemEquil_print_lvl > 0 && !m_doResPerturb) {
878 writelog(
"Residual: ElFracGoal ElFracCurrent Resid\n");
879 for (
size_t n = 0; n <
m_mm; n++) {
880 writelogf(
" % -14.7E % -14.7E % -10.5E\n",
881 elmFracGoal[n], elmFrac[n], resid[n]);
887 resid[
m_mm] = xx/xval - 1.0;
888 resid[m_skip] = yy/yval - 1.0;
890 if (DEBUG_MODE_ENABLED && ChemEquil_print_lvl > 0 && !m_doResPerturb) {
892 writelogf(
" XX : % -14.7E % -14.7E % -10.5E\n", xval, xx, resid[m_mm]);
893 writelogf(
" YY(%1d): % -14.7E % -14.7E % -10.5E\n", m_skip, yval, yy, resid[m_skip]);
899 doublereal xval, doublereal yval,
int loglevel)
903 size_t len = x.size();
907 doublereal rdx, dx, xsave;
908 doublereal atol = 1.e-10;
912 m_doResPerturb =
false;
913 for (n = 0; n < len; n++) {
915 dx = std::max(atol, fabs(xsave) * 1.0E-7);
926 for (m = 0; m < x.size(); m++) {
927 jac(m, n) = (r1[m] - r0[m])*rdx;
931 m_doResPerturb =
false;
937 double pressureConst)
939 double n_t_calc = 0.0;
950 for (
size_t k = 0; k <
m_kk; k++) {
951 tmp = - (
m_muSS_RT[k] + log(actCoeff[k]));
952 for (
size_t m = 0; m <
m_mm; m++) {
953 tmp +=
nAtoms(k,m) * x[m];
955 tmp = std::min(tmp, 100.0);
959 n_i_calc[k] = n_t * exp(tmp);
961 n_t_calc += n_i_calc[k];
963 for (
size_t m = 0; m <
m_mm; m++) {
965 for (
size_t k = 0; k <
m_kk; k++) {
966 eMolesCalc[m] +=
nAtoms(k,m) * n_i_calc[k];
983 bool modifiedMatrix =
false;
997 double pressureConst = s.
pressure();
998 copy(n_i.begin(), n_i.end(), Xmol_i_calc.begin());
1014 double elMolesTotal = 0.0;
1015 for (m = 0; m <
m_mm; m++) {
1016 elMolesTotal += elMoles[m];
1017 for (k = 0; k <
m_kk; k++) {
1018 eMolesFix[m] +=
nAtoms(k,m) * n_i[k];
1022 for (m = 0; m <
m_mm; m++) {
1023 if (elMoles[m] > 1.0E-70) {
1024 x[m] =
clip(x[m], -100.0, 50.0);
1026 x[m] =
clip(x[m], -1000.0, 50.0);
1033 double nAtomsMax = 1.0;
1037 for (k = 0; k <
m_kk; k++) {
1038 tmp = - (
m_muSS_RT[k] + log(actCoeff[k]));
1040 for (m = 0; m <
m_mm; m++) {
1044 nAtomsMax = std::max(nAtomsMax, sum2);
1053 if (DEBUG_MODE_ENABLED && ChemEquil_print_lvl > 0) {
1054 writelog(
"estimateEP_Brinkley::\n\n");
1059 writelog(
"Initial mole numbers and mu_SS:\n");
1060 writelog(
" Name MoleNum mu_SS actCoeff\n");
1061 for (k = 0; k <
m_kk; k++) {
1063 writelogf(
"%15s %13.5g %13.5g %13.5g\n",
1064 nnn.c_str(), n_i[k],
m_muSS_RT[k], actCoeff[k]);
1066 writelogf(
"Initial n_t = %10.5g\n", n_t);
1067 writelog(
"Comparison of Goal Element Abundance with Initial Guess:\n");
1068 writelog(
" eName eCurrent eGoal\n");
1069 for (m = 0; m <
m_mm; m++) {
1071 writelogf(
"%5s %13.5g %13.5g\n",nnn.c_str(), eMolesFix[m], elMoles[m]);
1074 for (m = 0; m <
m_mm; m++) {
1090 for (m = 0; m <
m_mm; m++) {
1097 if (DEBUG_MODE_ENABLED && ChemEquil_print_lvl > 0) {
1098 writelogf(
"START ITERATION %d:\n", iter);
1103 double n_t_calc =
calcEmoles(s, x, n_t, Xmol_i_calc, eMolesCalc, n_i_calc,
1106 for (k = 0; k <
m_kk; k++) {
1107 Xmol_i_calc[k] = n_i_calc[k]/n_t_calc;
1110 if (DEBUG_MODE_ENABLED && ChemEquil_print_lvl > 0) {
1111 writelog(
" Species: Calculated_Moles Calculated_Mole_Fraction\n");
1112 for (k = 0; k <
m_kk; k++) {
1114 writelogf(
"%15s: %10.5g %10.5g\n", nnn.c_str(), n_i_calc[k], Xmol_i_calc[k]);
1116 writelogf(
"%15s: %10.5g\n",
"Total Molar Sum", n_t_calc);
1117 writelogf(
"(iter %d) element moles bal: Goal Calculated\n", iter);
1118 for (m = 0; m <
m_mm; m++) {
1120 writelogf(
" %8s: %10.5g %10.5g \n", nnn.c_str(), elMoles[m], eMolesCalc[m]);
1126 bool normalStep =
true;
1131 for (m = 0; m <
m_mm; m++) {
1132 if (elMoles[m] > 0.001 * elMolesTotal) {
1133 if (eMolesCalc[m] > 1000. * elMoles[m]) {
1137 if (1000 * eMolesCalc[m] < elMoles[m]) {
1143 if (DEBUG_MODE_ENABLED && ChemEquil_print_lvl > 0) {
1145 writelogf(
" NOTE: iter(%d) Doing an abnormal step due to row %d\n", iter, iM);
1151 for (im = 0; im <
m_mm; im++) {
1152 m = m_orderVectorElements[im];
1155 if (elMoles[m] > 0.001 * elMolesTotal) {
1156 if (eMolesCalc[m] > 1000. * elMoles[m]) {
1160 if (1000 * eMolesCalc[m] < elMoles[m]) {
1167 if (n_t < (elMolesTotal / nAtomsMax)) {
1168 if (resid[m_mm] < 0.0) {
1171 }
else if (n_t > elMolesTotal) {
1172 resid[
m_mm] = std::min(resid[m_mm], 0.0);
1199 for (m = 0; m <
m_mm; m++) {
1203 nCutoff = 1.0E-9 * n_t_calc;
1204 if (DEBUG_MODE_ENABLED && ChemEquil_print_lvl > 0) {
1205 writelog(
" Lump Sum Elements Calculation: \n");
1207 for (m = 0; m <
m_mm; m++) {
1209 size_t kMSp2 =
npos;
1210 int nSpeciesWithElem = 0;
1211 for (k = 0; k <
m_kk; k++) {
1212 if (n_i_calc[k] > nCutoff) {
1213 if (fabs(
nAtoms(k,m)) > 0.001) {
1217 double factor = fabs(
nAtoms(kMSp,m) /
nAtoms(kMSp2,m));
1218 for (n = 0; n <
m_mm; n++) {
1219 if (fabs(factor *
nAtoms(kMSp2,n) -
nAtoms(kMSp,n)) > 1.0E-8) {
1230 if (DEBUG_MODE_ENABLED && ChemEquil_print_lvl > 0) {
1232 writelogf(
" %5s %3d : %5d %5d\n",nnn.c_str(), lumpSum[m], kMSp, kMSp2);
1239 for (im = 0; im <
m_mm; im++) {
1240 m = m_orderVectorElements[im];
1242 for (n = 0; n <
m_mm; n++) {
1244 for (k = 0; k <
m_kk; k++) {
1248 a1(m,m_mm) = eMolesCalc[m];
1249 a1(m_mm, m) = eMolesCalc[m];
1251 for (n = 0; n <=
m_mm; n++) {
1257 a1(m_mm, m_mm) = 0.0;
1263 for (im = 0; im <
m_mm; im++) {
1264 m = m_orderVectorElements[im];
1266 resid[m] = elMoles[m] - eMolesCalc[m];
1284 for (m = 0; m <
m_mm; m++) {
1285 if (a1(m,m) < 1.0E-50) {
1286 if (DEBUG_MODE_ENABLED && ChemEquil_print_lvl > 0) {
1287 writelogf(
" NOTE: Diagonalizing the analytical Jac row %d\n", m);
1289 for (n = 0; n <
m_mm; n++) {
1293 if (resid[m] > 0.0) {
1295 }
else if (resid[m] < 0.0) {
1304 resid[
m_mm] = n_t - n_t_calc;
1306 if (DEBUG_MODE_ENABLED && ChemEquil_print_lvl > 0) {
1308 for (m = 0; m <=
m_mm; m++) {
1310 for (n = 0; n <=
m_mm; n++) {
1317 tmp = resid[
m_mm] /(n_t + 1.0E-15);
1319 if (DEBUG_MODE_ENABLED && ChemEquil_print_lvl > 0) {
1320 writelogf(
"(it %d) Convergence = %g\n", iter, sum);
1337 for (m = 0; m <=
m_mm; m++) {
1339 for (n = 0; n <=
m_mm; n++) {
1340 tmp += fabs(a1(m,n));
1342 if (m < m_mm && tmp < 1.0E-30) {
1343 if (DEBUG_MODE_ENABLED && ChemEquil_print_lvl > 0) {
1344 writelogf(
" NOTE: Diagonalizing row %d\n", m);
1346 for (n = 0; n <=
m_mm; n++) {
1354 for (n = 0; n <=
m_mm; n++) {
1360 if (DEBUG_MODE_ENABLED && ChemEquil_print_lvl > 0) {
1362 for (m = 0; m <=
m_mm; m++) {
1364 for (n = 0; n <=
m_mm; n++) {
1391 modifiedMatrix =
false;
1392 for (m = 0; m <
m_mm; m++) {
1393 size_t sameAsRow =
npos;
1394 for (
size_t im = 0; im < m; im++) {
1395 bool theSame =
true;
1396 for (n = 0; n <
m_mm; n++) {
1397 if (fabs(a1(m,n) - a1(im,n)) > 1.0E-7) {
1406 if (sameAsRow !=
npos || lumpSum[m]) {
1407 if (DEBUG_MODE_ENABLED && ChemEquil_print_lvl > 0) {
1409 writelogf(
"Lump summing row %d, due to rank deficiency analysis\n", m);
1410 }
else if (sameAsRow !=
npos) {
1411 writelogf(
"Identified that rows %d and %d are the same\n", m, sameAsRow);
1414 modifiedMatrix =
true;
1415 for (n = 0; n <
m_mm; n++) {
1417 a1(m,m) += fabs(a1(m,n));
1424 if (DEBUG_MODE_ENABLED && ChemEquil_print_lvl > 0 && modifiedMatrix) {
1425 writelog(
"Row Summed, MODIFIED Matrix:\n");
1426 for (m = 0; m <=
m_mm; m++) {
1428 for (n = 0; n <=
m_mm; n++) {
1439 if (DEBUG_MODE_ENABLED) {
1440 writelog(
"Matrix is SINGULAR.ERROR\n", ChemEquil_print_lvl);
1443 throw CanteraError(
"equilibrate:estimateEP_Brinkley()",
1444 "Jacobian is singular. \nTry adding more species, "
1445 "changing the elemental composition slightly, \nor removing "
1446 "unused elements.");
1455 for (m = 0; m <
m_mm; m++) {
1456 if (resid[m] > 1.0) {
1457 beta = std::min(beta, 1.0 / resid[m]);
1459 if (resid[m] < -1.0) {
1460 beta = std::min(beta, -1.0 / resid[m]);
1463 if (DEBUG_MODE_ENABLED && ChemEquil_print_lvl > 0) {
1465 writelogf(
"(it %d) Beta = %g\n", iter, beta);
1472 for (m = 0; m <
m_mm; m++) {
1473 x[m] += beta * resid[m];
1475 n_t *= exp(beta * resid[m_mm]);
1477 if (DEBUG_MODE_ENABLED && ChemEquil_print_lvl > 0) {
1478 writelogf(
"(it %d) OLD_SOLUTION NEW SOLUTION (undamped updated)\n", iter);
1479 for (m = 0; m <
m_mm; m++) {
1481 writelogf(
" %5s %10.5g %10.5g %10.5g\n", eee.c_str(), x_old[m], x[m], resid[m]);
1483 writelogf(
" n_t %10.5g %10.5g %10.5g \n", x_old[m_mm], n_t, exp(resid[m_mm]));
1486 if (DEBUG_MODE_ENABLED && ChemEquil_print_lvl > 0) {
1491 writelogf(
" ChemEquil::estimateEP_Brinkley() SUCCESS: equilibrium found at T = %g, Pres = %g\n",
1494 writelogf(
" ChemEquil::estimateEP_Brinkley() FAILURE: equilibrium not found at T = %g, Pres = %g\n",
1507 if (fabs(elMolesGoal[
m_eloc]) > 1.0E-20) {
1513 size_t maxPosEloc =
npos;
1514 size_t maxNegEloc =
npos;
1515 double maxPosVal = -1.0;
1516 double maxNegVal = -1.0;
1517 if (DEBUG_MODE_ENABLED && ChemEquil_print_lvl > 0) {
1518 for (k = 0; k <
m_kk; k++) {
1519 if (
nAtoms(k,m_eloc) > 0.0) {
1525 if (
nAtoms(k,m_eloc) < 0.0) {
1534 double sumPos = 0.0;
1535 double sumNeg = 0.0;
1536 for (k = 0; k <
m_kk; k++) {
1537 if (
nAtoms(k,m_eloc) > 0.0) {
1540 if (
nAtoms(k,m_eloc) < 0.0) {
1546 if (sumPos >= sumNeg) {
1547 if (sumPos <= 0.0) {
1550 double factor = (elMolesGoal[
m_eloc] + sumNeg) / sumPos;
1551 if (DEBUG_MODE_ENABLED && ChemEquil_print_lvl > 0 && factor < 0.9999999999) {
1553 writelogf(
"adjustEloc: adjusted %s and friends from %g to %g to ensure neutrality condition\n",
1557 for (k = 0; k <
m_kk; k++) {
1558 if (
nAtoms(k,m_eloc) > 0.0) {
1563 double factor = (-elMolesGoal[
m_eloc] + sumPos) / sumNeg;
1564 if (DEBUG_MODE_ENABLED && ChemEquil_print_lvl > 0 && factor < 0.9999999999) {
1566 writelogf(
"adjustEloc: adjusted %s and friends from %g to %g to ensure neutrality condition\n",
1570 for (k = 0; k <
m_kk; k++) {
1571 if (
nAtoms(k,m_eloc) < 0.0) {
doublereal nAtoms(size_t k, size_t m) const
Number of atoms of element m in species k.
EquilOpt options
Options controlling how the calculation is carried out.
virtual doublereal density() const
Density (kg/m^3).
std::string int2str(const int n, const std::string &fmt)
Convert an int to a string using a format converter.
void restoreState(const vector_fp &state)
Restore a state saved on a previous call to saveState.
vector_fp m_muSS_RT
Dimensionless values of the Gibbs free energy for the standard state of each species, at the temperature and pressure of the solution (the star standard state).
size_t BasisOptimize(int *usedZeroedSpecies, bool doFormRxn, MultiPhase *mphase, std::vector< size_t > &orderVectorSpecies, std::vector< size_t > &orderVectorElements, vector_fp &formRxnMatrix)
Choose the optimum basis of species for the equilibrium calculations.
thermo_t * m_phase
Pointer to the ThermoPhase object used to initialize this object.
doublereal relTolerance
Relative tolerance.
size_t nElements() const
Number of elements.
const doublereal OneAtm
One atmosphere [Pa].
int setInitialMoles(thermo_t &s, vector_fp &elMoleGoal, int loglevel=0)
Estimate the initial mole numbers.
const size_t npos
index returned by functions to indicate "no position"
size_t m_kk
number of species in the phase
void addPhase(ThermoPhase *p, doublereal moles)
Add a phase to the mixture.
int equilibrate(thermo_t &s, const char *XY, bool useThermoPhaseElementPotentials=false, int loglevel=0)
doublereal atomicWeight(size_t m) const
Atomic weight of element m.
T clip(const T &value, const T &lower, const T &upper)
Clip value such that lower <= value <= upper.
int solve(DenseMatrix &A, double *b, size_t nrhs, size_t ldb)
Solve Ax = b. Array b is overwritten on exit with x.
void initialize(thermo_t &s)
size_t m_nComponents
This is equal to the rank of the stoichiometric coefficient matrix when it is computed.
void getMoleFractions(doublereal *const x) const
Get the species mole fraction vector.
void equilResidual(thermo_t &s, const vector_fp &x, const vector_fp &elmtotal, vector_fp &resid, double xval, double yval, int loglevel=0)
Evaluates the residual vector F, of length m_mm.
void update(const thermo_t &s)
Update internally stored state information.
int iterations
Iteration counter.
Base class for a phase with thermodynamic properties.
std::vector< int > vector_int
Vector of ints.
void setToEquilState(thermo_t &s, const vector_fp &x, doublereal t)
A class for multiphase mixtures.
void writelogf(const char *fmt,...)
Write a formatted message to the screen.
size_t m_eloc
Index of the element id corresponding to the electric charge of each species.
virtual doublereal maxTemp(size_t k=npos) const
Maximum temperature for which the thermodynamic data for the species are valid.
std::string fp2str(const double x, const std::string &fmt)
Convert a double into a c++ string.
bool getElementPotentials(doublereal *lambda) const
Returns the element potentials stored in the ThermoPhase object.
virtual void getChemPotentials(doublereal *mu) const
Get the species chemical potentials. Units: J/kmol.
doublereal absElemTol
Abs Tol in element number.
double m_elemFracCutoff
element fractional cutoff, below which the element will be zeroed.
int estimateEP_Brinkley(thermo_t &s, vector_fp &lambda, vector_fp &elMoles)
Base class for exceptions thrown by Cantera classes.
virtual void setMoleFractions(const doublereal *const x)
Set the mole fractions to the specified values There is no restriction on the sum of the mole fractio...
int estimateElementPotentials(thermo_t &s, vector_fp &lambda, vector_fp &elMolesGoal, int loglevel=0)
Generate a starting estimate for the element potentials.
size_t m_mm
number of elements in the phase
doublereal dot(InputIter x_begin, InputIter x_end, InputIter2 y_begin)
Function that calculates a templated inner product.
virtual doublereal refPressure() const
Returns the reference pressure in Pa.
size_t nSpecies() const
Returns the number of species in the phase.
virtual doublereal pressure() const
Return the thermodynamic pressure (Pa).
doublereal moleFraction(size_t k) const
Return the mole fraction of a single species.
doublereal temperature() const
Temperature (K).
virtual void setPressure(doublereal p)
Set the internally stored pressure (Pa) at constant temperature and composition.
std::vector< double > vector_fp
Turn on the use of stl vectors for the basic array type within cantera Vector of doubles.
virtual void setTemperature(const doublereal temp)
Set the internally stored temperature of the phase (K).
void scale(InputIter begin, InputIter end, OutputIter out, S scale_factor)
Multiply elements of an array by a scale factor.
vector_fp m_lambda
Current value of the dimensional element potentials -> length = m_mm.
const doublereal GasConstant
Universal Gas Constant. [J/kmol/K].
void init()
Process phases and build atomic composition array.
virtual void getActivityCoefficients(doublereal *ac) const
Get the array of non-dimensional molar-based activity coefficients at the current solution temperatur...
doublereal nAtoms(size_t k, size_t m) const
number of atoms of element m in species k.
Contains declarations for string manipulation functions within Cantera.
#define DATA_PTR(vec)
Creates a pointer to the start of the raw data for a vector.
std::string elementName(size_t m) const
Name of the element with index m.
void saveState(vector_fp &state) const
Save the current internal state of the phase Write to vector 'state' the current internal state...
void setElementPotentials(const vector_fp &lambda)
Stores the element potentials in the ThermoPhase object.
vector_fp m_molefractions
Current value of the mole fractions in the single phase.
double calcEmoles(thermo_t &s, vector_fp &x, const double &n_t, const vector_fp &Xmol_i_calc, vector_fp &eMolesCalc, vector_fp &n_i_calc, double pressureConst)
Given a vector of dimensionless element abundances, this routine calculates the moles of the elements...
int maxIterations
Maximum number of iterations.
void writelog(const std::string &msg)
Write a message to the screen.
int _equilflag(const char *xy)
map property strings to integers
virtual void setToEquilState(const doublereal *lambda_RT)
This method is used by the ChemEquil equilibrium solver.
size_t ElemRearrange(size_t nComponents, const vector_fp &elementAbundances, MultiPhase *mphase, std::vector< size_t > &orderVectorSpecies, std::vector< size_t > &orderVectorElements)
Handles the potential rearrangement of the constraint equations represented by the Formula Matrix...
std::string speciesName(size_t k) const
Name of the species with index k.
virtual void getGibbs_RT(doublereal *grt) const
Get the nondimensional Gibbs functions for the species in their standard states at the current T and ...
A class for full (non-sparse) matrices with Fortran-compatible data storage, which adds matrix operat...
int dampStep(thermo_t &s, vector_fp &oldx, double oldf, vector_fp &grad, vector_fp &step, vector_fp &x, double &f, vector_fp &elmols, double xval, double yval)
Find an acceptable step size and take it.
virtual doublereal minTemp(size_t k=npos) const
Minimum temperature for which the thermodynamic data for the species or phase are valid...
void save()
Function to put this error onto Cantera's error stack.