24 int Cantera::ChemEquil_print_lvl = 0;
31 string flag = string(xy);
34 }
else if (flag ==
"TV") {
36 }
else if (flag ==
"HP") {
38 }
else if (flag ==
"UV") {
40 }
else if (flag ==
"SP") {
42 }
else if (flag ==
"SV") {
44 }
else if (flag ==
"UP") {
47 throw CanteraError(
"_equilflag",
"unknown property pair "+flag);
52 ChemEquil::ChemEquil() : m_skip(
npos), m_elementTotalSum(1.0),
54 m_elemFracCutoff(1.0E-100),
60 m_elementTotalSum(1.0),
62 m_elemFracCutoff(1.0E-100),
68 ChemEquil::~ChemEquil()
85 m_elementmolefracs.resize(
m_mm);
87 m_jwork1.resize(
m_mm+2);
88 m_jwork2.resize(
m_mm+2);
89 m_startSoln.resize(
m_mm+1);
94 m_orderVectorElements.resize(
m_mm);
96 for (
size_t m = 0; m <
m_mm; m++) {
97 m_orderVectorElements[m] = m;
99 m_orderVectorSpecies.resize(m_kk);
100 for (
size_t k = 0; k <
m_kk; k++) {
101 m_orderVectorSpecies[k] = k;
107 for (
size_t m = 0; m <
m_mm; m++) {
108 for (
size_t k = 0; k <
m_kk; k++) {
119 if (mneg !=
npos && mneg != m)
121 "negative atom numbers allowed for only one element");
131 +
" atoms of element "
133 ", but this element is not an electron.\n"));
140 for (
size_t k = 0; k <
m_kk; k++) {
141 for (
size_t m = 0; m <
m_mm; m++) {
142 m_comp[k*m_mm + m] = s.
nAtoms(k,m);
148 const vector_fp& lambda_RT, doublereal t)
151 fill(m_mu_RT.begin(), m_mu_RT.end(), 0.0);
152 for (
size_t k = 0; k <
m_kk; k++)
153 for (
size_t m = 0; m <
m_mm; m++) {
154 m_mu_RT[k] += lambda_RT[m]*
nAtoms(k,m);
177 for (
size_t m = 0; m <
m_mm; m++) {
178 m_elementmolefracs[m] = 0.0;
179 for (
size_t k = 0; k <
m_kk; k++) {
187 sum += m_elementmolefracs[m];
190 m_elementTotalSum = sum;
192 for (
size_t m = 0; m <
m_mm; m++) {
193 m_elementmolefracs[m] /= sum;
209 e.setInitialMixMoles(loglevel-1);
216 m_component[m] = e.componentIndex(m);
218 for (
size_t k = 0; k <
m_kk; k++) {
233 if (ChemEquil_print_lvl > 0) {
234 writelog(
"setInitialMoles: Estimated Mole Fractions\n");
237 for (
size_t k = 0; k <
m_kk; k++) {
240 writelogf(
" %-12s % -10.5g\n", nnn.c_str(), mf);
242 writelog(
" Element_Name ElementGoal ElementMF\n");
243 for (
size_t m = 0; m <
m_mm; m++) {
246 nnn.c_str(), elMoleGoal[m], m_elementmolefracs[m]);
281 for (
size_t n = 0; n < s.
nSpecies(); n++) {
282 if (xMF_est[n] < 1.0E-20) {
283 xMF_est[n] = 1.0E-20;
292 int usedZeroedSpecies = 0;
295 &mp, m_orderVectorSpecies,
296 m_orderVectorElements, formRxnMatrix);
299 size_t k = m_orderVectorSpecies[m];
301 if (xMF_est[k] < 1.0E-8) {
309 m_orderVectorSpecies, m_orderVectorElements);
310 if (nct != m_nComponents) {
311 throw CanteraError(
"ChemEquil::estimateElementPotentials",
317 scale(mu_RT.begin(), mu_RT.end(), mu_RT.begin(), rrt);
320 if (ChemEquil_print_lvl > 0) {
322 int isp = m_component[m];
324 writelogf(
"isp = %d, %s\n", isp, nnn.c_str());
331 for (
size_t n = 0; n < s.
nSpecies(); n++) {
334 n, nnn.c_str(), xMF_est[n], mu_RT[n]);
341 aa(m,n) =
nAtoms(m_component[m], m_orderVectorElements[n]);
343 b[m] = mu_RT[m_component[m]];
349 addLogEntry(
"failed to estimate initial element potentials.");
354 lambda_RT[m_orderVectorElements[m]] = b[m];
356 for (
size_t m = m_nComponents; m <
m_mm; m++) {
357 lambda_RT[m_orderVectorElements[m]] = 0.0;
361 for (
size_t m = 0; m <
m_mm; m++) {
368 if (ChemEquil_print_lvl > 0) {
369 writelog(
" id CompSpecies ChemPot EstChemPot Diff\n");
371 int isp = m_component[m];
374 for (
size_t n = 0; n <
m_mm; n++) {
375 tmp +=
nAtoms(isp, n) * lambda_RT[n];
377 writelogf(
"%3d %16s %10.5g %10.5g %10.5g\n",
378 m, sname.c_str(), mu_RT[isp], tmp, tmp - mu_RT[isp]);
382 for (
size_t m = 0; m <
m_mm; m++) {
384 writelogf(
" %3d %6s %10.5g\n", m, ename.c_str(), lambda_RT[m]);
395 bool useThermoPhaseElementPotentials,
int loglevel)
400 copy(m_elementmolefracs.begin(), m_elementmolefracs.end(),
401 elMolesGoal.begin());
402 return equilibrate(s, XY, elMolesGoal, useThermoPhaseElementPotentials,
408 bool useThermoPhaseElementPotentials,
411 doublereal xval, yval, tmp;
414 bool tempFixed =
true;
425 "Input ThermoPhase is incompatible with initialization");
440 m_p1.reset(
new TemperatureCalculator<thermo_t>);
441 m_p2.reset(
new PressureCalculator<thermo_t>);
446 m_p1.reset(
new EnthalpyCalculator<thermo_t>);
447 m_p2.reset(
new PressureCalculator<thermo_t>);
452 m_p1.reset(
new EntropyCalculator<thermo_t>);
453 m_p2.reset(
new PressureCalculator<thermo_t>);
458 m_p1.reset(
new EntropyCalculator<thermo_t>);
459 m_p2.reset(
new DensityCalculator<thermo_t>);
463 m_p1.reset(
new TemperatureCalculator<thermo_t>);
464 m_p2.reset(
new DensityCalculator<thermo_t>);
469 m_p1.reset(
new IntEnergyCalculator<thermo_t>);
470 m_p2.reset(
new DensityCalculator<thermo_t>);
476 throw CanteraError(
"equilibrate",
"illegal property pair.");
479 addLogEntry(
"Problem type",
"fixed "+m_p1->symbol()+
", "+m_p2->symbol());
491 throw CanteraError(
"ChemEquil",
"Specified temperature ("
503 xval = m_p1->value(s);
504 yval = m_p2->value(s);
507 size_t nvar = mm + 1;
522 m = m_orderVectorElements[im];
523 if (elMolesGoal[m] > tmp) {
525 tmp = elMolesGoal[m];
530 "Element Abundance Vector is zeroed");
538 for (
size_t k = 0; k <
m_kk; k++) {
549 doublereal tmaxPhase = s.
maxTemp();
550 doublereal tminPhase = s.
minTemp();
561 if (tmin < tminPhase) {
564 if (tmin > tmaxPhase) {
565 tmin = tmaxPhase - 20;
568 if (tmax > tmaxPhase) {
571 if (tmax < tminPhase) {
572 tmax = tminPhase + 20;
575 doublereal slope, phigh, plow, pval, dt;
584 phigh = m_p1->value(s);
588 plow = m_p1->value(s);
591 doublereal t0 = 0.5*(tmin + tmax);
595 for (
int it = 0; it < 10; it++) {
599 pval = m_p1->value(s);
615 slope = (phigh - plow)/(tmax - tmin);
616 dt = (xval - pval)/slope;
619 if (fabs(dt) < 50.0) {
628 if ((t0 + dt) < tminPhase) {
629 dt = 0.5*((t0) + tminPhase) - t0;
631 if ((t0 + dt) > tmaxPhase) {
632 dt = 0.5*((t0) + tmaxPhase) - t0;
636 if (t0 <= tminPhase || t0 >= tmaxPhase) {
637 printf(
"We shouldn't be here\n");
644 printf(
"t0 - we are here %g\n", t0);
662 if (useThermoPhaseElementPotentials) {
669 for (m = 0; m <
m_mm; m++) {
702 addLogEntry(
"estimateEP_Brinkley didn't converge in given max iterations");
703 }
else if (info == -3) {
704 addLogEntry(
"estimateEP_Brinkley had a singular Jacobian. Continuing anyway");
730 for (m = 0; m < mm; m++) {
741 above[mm] = log(s.
maxTemp() + 25.0);
742 below[mm] = log(s.
minTemp() - 25.0);
750 doublereal fctr = 1.0, newval;
756 if (iter > 1 && loglevel > 0) {
766 f = 0.5*
dot(res_trial.begin(), res_trial.end(), res_trial.begin());
770 equilJacobian(s, x, elMolesGoal, jac, xval, yval);
773 if (ChemEquil_print_lvl > 0) {
774 writelogf(
"Jacobian matrix %d:\n", iter);
775 for (m = 0; m <=
m_mm; m++) {
777 for (n = 0; n <=
m_mm; n++) {
783 string nnn = eNames[m];
784 sprintf(xName,
"x_%-10s", nnn.c_str());
786 sprintf(xName,
"x_XX");
789 sprintf(xName,
"x_ELOC");
792 sprintf(xName,
"x_YY");
795 writelogf(
" = - (%10.5g)\n", res_trial[m]);
800 copy(x.begin(), x.end(), oldx.begin());
802 scale(res_trial.begin(), res_trial.end(), res_trial.begin(), -1.0);
817 "Jacobian is singular. \nTry adding more species, "
818 "changing the elemental composition slightly, \nor removing "
826 for (m = 0; m < nvar; m++) {
827 newval = x[m] + res_trial[m];
828 if (newval > above[m]) {
830 std::min(fctr,0.8*(above[m] - x[m])/(newval - x[m])));
831 }
else if (newval < below[m]) {
832 if (m <
m_mm && (m != m_skip)) {
834 if (x[m] < below[m] + 50.) {
835 res_trial[m] = below[m] - x[m];
838 fctr = std::min(fctr, 0.8*(x[m] - below[m])/(x[m] - newval));
843 if (fabs(res_trial[mm]) > 0.2) {
844 fctr = std::min(fctr, 0.2/fabs(res_trial[mm]));
849 addLogEntry(
"WARNING: factor to keep solution in bounds", fctr);
851 if (ChemEquil_print_lvl > 0) {
852 writelogf(
"WARNING Soln Damping because of bounds: %g\n", fctr);
858 scale(res_trial.begin(), res_trial.end(), res_trial.begin(), fctr);
860 if (!
dampStep(s, oldx, oldf, grad, res_trial,
861 x, f, elMolesGoal , xval, yval)) {
864 addLogEntry(
"dampStep",
"Failed 3 times. Giving up.");
869 "Cannot find an acceptable Newton damping coefficient.");
880 f = 0.5*
dot(res_trial.begin(), res_trial.end(), res_trial.begin());
881 doublereal xx, yy, deltax, deltay;
884 deltax = (xx - xval)/xval;
885 deltay = (yy - yval)/yval;
886 doublereal rmax = 0.0;
887 bool passThis =
true;
888 for (m = 0; m < nvar; m++) {
911 if (fabs(res_trial[m]) > tval) {
915 if (iter > 0 && passThis
923 addLogEntry(
"Relative error in "+m_p1->symbol(),deltax);
924 addLogEntry(
"Relative error in "+m_p2->symbol(),deltay);
929 for (m = 0; m <
m_mm; m++) {
937 adjustEloc(s, elMolesGoal);
945 addLogEntry(
"Saving Element Potentials to ThermoPhase Object");
981 double& f,
vector_fp& elmols,
double xval,
double yval)
989 for (
size_t m = 0; m <
m_mm; m++) {
991 if (step[m] > 1.25) {
992 damp = std::min(damp, 1.25 /step[m]);
994 if (step[m] < -1.25) {
995 damp = std::min(damp, -1.25 / step[m]);
998 if (step[m] > 0.75) {
999 damp = std::min(damp, 0.75 /step[m]);
1001 if (step[m] < -0.75) {
1002 damp = std::min(damp, -0.75 / step[m]);
1010 for (
size_t m = 0; m < x.size(); m++) {
1011 x[m] = oldx[m] + damp * step[m];
1014 if (ChemEquil_print_lvl > 0) {
1015 writelogf(
"Solution Unknowns: damp = %g\n", damp);
1017 for (
size_t m = 0; m <
m_mm; m++) {
1018 writelogf(
" % -10.5g % -10.5g % -10.5g\n", x[m], oldx[m], step[m]);
1027 doublereal xval, doublereal yval,
int loglevel)
1033 doublereal temp = exp(x[
m_mm]);
1037 vector_fp& elmFrac = m_elementmolefracs;
1038 for (
size_t n = 0; n <
m_mm; n++) {
1039 size_t m = m_orderVectorElements[n];
1042 resid[m] = x[m] + 1000.0;
1051 if (elmFracGoal[m] < 1.0E-10 || elmFrac[m] < 1.0E-10 || m ==
m_eloc) {
1052 resid[m] = elmFracGoal[m] - elmFrac[m];
1054 resid[m] = log((1.0 + elmFracGoal[m]) / (1.0 + elmFrac[m]));
1059 +
fp2str(elmFracGoal[m])+
")");
1063 if (ChemEquil_print_lvl > 0 && !m_doResPerturb) {
1064 writelog(
"Residual: ElFracGoal ElFracCurrent Resid\n");
1065 for (
int n = 0; n <
m_mm; n++) {
1066 writelogf(
" % -14.7E % -14.7E % -10.5E\n",
1067 elmFracGoal[n], elmFrac[n], resid[n]);
1072 xx = m_p1->value(s);
1073 yy = m_p2->value(s);
1074 resid[
m_mm] = xx/xval - 1.0;
1075 resid[m_skip] = yy/yval - 1.0;
1085 if (ChemEquil_print_lvl > 0 && !m_doResPerturb) {
1087 writelogf(
" XX : % -14.7E % -14.7E % -10.5E\n", xval, xx, resid[m_mm]);
1088 writelogf(
" YY(%1d): % -14.7E % -14.7E % -10.5E\n", m_skip, yval, yy, resid[m_skip]);
1095 doublereal xval, doublereal yval,
int loglevel)
1102 size_t len = x.size();
1106 doublereal rdx, dx, xsave, dx2;
1107 doublereal atol = 1.e-10;
1111 m_doResPerturb =
false;
1112 for (n = 0; n < len; n++) {
1115 dx2 = fabs(xsave) * 1.0E-7;
1129 for (m = 0; m < x.size(); m++) {
1130 jac(m, n) = (r1[m] - r0[m])*rdx;
1134 m_doResPerturb =
false;
1143 double pressureConst)
1145 double n_t_calc = 0.0;
1156 for (
size_t k = 0; k <
m_kk; k++) {
1157 tmp = - (
m_muSS_RT[k] + log(actCoeff[k]));
1158 for (
size_t m = 0; m <
m_mm; m++) {
1159 tmp +=
nAtoms(k,m) * x[m];
1167 n_i_calc[k] = n_t * exp(tmp);
1169 n_t_calc += n_i_calc[k];
1171 for (
size_t m = 0; m <
m_mm; m++) {
1172 eMolesCalc[m] = 0.0;
1173 for (
size_t k = 0; k <
m_kk; k++) {
1174 eMolesCalc[m] +=
nAtoms(k,m) * n_i_calc[k];
1191 bool modifiedMatrix =
false;
1192 size_t neq =
m_mm+1;
1205 double pressureConst = s.
pressure();
1206 copy(n_i.begin(), n_i.end(), Xmol_i_calc.begin());
1222 double elMolesTotal = 0.0;
1223 for (m = 0; m <
m_mm; m++) {
1224 elMolesTotal += elMoles[m];
1225 for (k = 0; k <
m_kk; k++) {
1226 eMolesFix[m] +=
nAtoms(k,m) * n_i[k];
1230 for (m = 0; m <
m_mm; m++) {
1234 if (elMoles[m] > 1.0E-70) {
1239 if (x[m] < -1000.) {
1248 double nAtomsMax = 1.0;
1252 for (k = 0; k <
m_kk; k++) {
1253 tmp = - (
m_muSS_RT[k] + log(actCoeff[k]));
1255 for (m = 0; m <
m_mm; m++) {
1259 if (sum2 > nAtomsMax) {
1273 if (ChemEquil_print_lvl > 0) {
1274 writelog(
"estimateEP_Brinkley::\n\n");
1279 writelog(
"Initial mole numbers and mu_SS:\n");
1280 writelog(
" Name MoleNum mu_SS actCoeff\n");
1281 for (k = 0; k <
m_kk; k++) {
1283 writelogf(
"%15s %13.5g %13.5g %13.5g\n",
1284 nnn.c_str(), n_i[k],
m_muSS_RT[k], actCoeff[k]);
1286 writelogf(
"Initial n_t = %10.5g\n", n_t);
1287 writelog(
"Comparison of Goal Element Abundance with Initial Guess:\n");
1288 writelog(
" eName eCurrent eGoal\n");
1289 for (m = 0; m <
m_mm; m++) {
1291 writelogf(
"%5s %13.5g %13.5g\n",nnn.c_str(), eMolesFix[m], elMoles[m]);
1295 for (m = 0; m <
m_mm; m++) {
1311 for (m = 0; m <
m_mm; m++) {
1319 if (ChemEquil_print_lvl > 0) {
1320 writelogf(
"START ITERATION %d:\n", iter);
1326 double n_t_calc =
calcEmoles(s, x, n_t, Xmol_i_calc, eMolesCalc, n_i_calc,
1329 for (k = 0; k <
m_kk; k++) {
1330 Xmol_i_calc[k] = n_i_calc[k]/n_t_calc;
1335 if (ChemEquil_print_lvl > 0) {
1336 writelog(
" Species: Calculated_Moles Calculated_Mole_Fraction\n");
1337 for (k = 0; k <
m_kk; k++) {
1339 writelogf(
"%15s: %10.5g %10.5g\n", nnn.c_str(), n_i_calc[k], Xmol_i_calc[k]);
1341 writelogf(
"%15s: %10.5g\n",
"Total Molar Sum", n_t_calc);
1342 writelogf(
"(iter %d) element moles bal: Goal Calculated\n", iter);
1343 for (m = 0; m <
m_mm; m++) {
1344 string nnn = eNames[m];
1345 writelogf(
" %8s: %10.5g %10.5g \n", nnn.c_str(), elMoles[m], eMolesCalc[m]);
1352 bool normalStep =
true;
1357 for (m = 0; m <
m_mm; m++) {
1358 if (elMoles[m] > 0.001 * elMolesTotal) {
1359 if (eMolesCalc[m] > 1000. * elMoles[m]) {
1363 if (1000 * eMolesCalc[m] < elMoles[m]) {
1369 if (DEBUG_MODE_ENABLED && ChemEquil_print_lvl > 0) {
1371 writelogf(
" NOTE: iter(%d) Doing an abnormal step due to row %d\n", iter, iM);
1377 for (im = 0; im <
m_mm; im++) {
1378 m = m_orderVectorElements[im];
1381 if (elMoles[m] > 0.001 * elMolesTotal) {
1382 if (eMolesCalc[m] > 1000. * elMoles[m]) {
1386 if (1000 * eMolesCalc[m] < elMoles[m]) {
1393 if (n_t < (elMolesTotal / nAtomsMax)) {
1394 if (resid[m_mm] < 0.0) {
1397 }
else if (n_t > elMolesTotal) {
1398 if (resid[m_mm] > 0.0) {
1402 goto updateSolnVector;
1430 for (m = 0; m <
m_mm; m++) {
1434 nCutoff = 1.0E-9 * n_t_calc;
1436 writelog(
" Lump Sum Elements Calculation: \n", ChemEquil_print_lvl);
1438 for (m = 0; m <
m_mm; m++) {
1440 size_t kMSp2 =
npos;
1441 int nSpeciesWithElem = 0;
1442 for (k = 0; k <
m_kk; k++) {
1443 if (n_i_calc[k] > nCutoff) {
1444 if (fabs(
nAtoms(k,m)) > 0.001) {
1448 double factor = fabs(
nAtoms(kMSp,m) /
nAtoms(kMSp2,m));
1449 for (n = 0; n <
m_mm; n++) {
1450 if (fabs(factor *
nAtoms(kMSp2,n) -
nAtoms(kMSp,n)) > 1.0E-8) {
1462 if (ChemEquil_print_lvl > 0) {
1463 string nnn = eNames[m];
1464 writelogf(
" %5s %3d : %5d %5d\n",nnn.c_str(), lumpSum[m], kMSp, kMSp2);
1472 for (im = 0; im <
m_mm; im++) {
1473 m = m_orderVectorElements[im];
1475 for (n = 0; n <
m_mm; n++) {
1477 for (k = 0; k <
m_kk; k++) {
1481 a1(m,m_mm) = eMolesCalc[m];
1482 a1(m_mm, m) = eMolesCalc[m];
1484 for (n = 0; n <=
m_mm; n++) {
1490 a1(m_mm, m_mm) = 0.0;
1496 for (im = 0; im <
m_mm; im++) {
1497 m = m_orderVectorElements[im];
1499 resid[m] = elMoles[m] - eMolesCalc[m];
1517 for (m = 0; m <
m_mm; m++) {
1518 if (a1(m,m) < 1.0E-50) {
1520 if (ChemEquil_print_lvl > 0) {
1521 writelogf(
" NOTE: Diagonalizing the analytical Jac row %d\n", m);
1524 for (n = 0; n <
m_mm; n++) {
1528 if (resid[m] > 0.0) {
1530 }
else if (resid[m] < 0.0) {
1539 resid[
m_mm] = n_t - n_t_calc;
1542 if (ChemEquil_print_lvl > 0) {
1544 for (m = 0; m <=
m_mm; m++) {
1546 for (n = 0; n <=
m_mm; n++) {
1554 tmp = resid[
m_mm] /(n_t + 1.0E-15);
1557 if (ChemEquil_print_lvl > 0) {
1558 writelogf(
"(it %d) Convergence = %g\n", iter, sum);
1576 for (m = 0; m <=
m_mm; m++) {
1578 for (n = 0; n <=
m_mm; n++) {
1579 tmp += fabs(a1(m,n));
1581 if (m < m_mm && tmp < 1.0E-30) {
1583 if (ChemEquil_print_lvl > 0) {
1584 writelogf(
" NOTE: Diagonalizing row %d\n", m);
1587 for (n = 0; n <=
m_mm; n++) {
1595 for (n = 0; n <=
m_mm; n++) {
1602 if (ChemEquil_print_lvl > 0) {
1604 for (m = 0; m <=
m_mm; m++) {
1606 for (n = 0; n <=
m_mm; n++) {
1634 modifiedMatrix =
false;
1635 for (m = 0; m <
m_mm; m++) {
1636 size_t sameAsRow =
npos;
1637 for (
size_t im = 0; im < m; im++) {
1638 bool theSame =
true;
1639 for (n = 0; n <
m_mm; n++) {
1640 if (fabs(a1(m,n) - a1(im,n)) > 1.0E-7) {
1649 if (sameAsRow !=
npos || lumpSum[m]) {
1651 if (ChemEquil_print_lvl > 0) {
1653 writelogf(
"Lump summing row %d, due to rank deficiency analysis\n", m);
1654 }
else if (sameAsRow !=
npos) {
1655 writelogf(
"Identified that rows %d and %d are the same\n", m, sameAsRow);
1659 modifiedMatrix =
true;
1660 for (n = 0; n <
m_mm; n++) {
1662 a1(m,m) += fabs(a1(m,n));
1669 if (DEBUG_MODE_ENABLED && ChemEquil_print_lvl > 0 && modifiedMatrix) {
1670 writelog(
"Row Summed, MODIFIED Matrix:\n");
1671 for (m = 0; m <=
m_mm; m++) {
1673 for (n = 0; n <=
m_mm; n++) {
1684 addLogEntry(
"estimateEP_Brinkley:Jacobian is singular.");
1686 writelog(
"Matrix is SINGULAR.ERROR\n", ChemEquil_print_lvl);
1689 throw CanteraError(
"equilibrate:estimateEP_Brinkley()",
1690 "Jacobian is singular. \nTry adding more species, "
1691 "changing the elemental composition slightly, \nor removing "
1692 "unused elements.");
1702 for (m = 0; m <
m_mm; m++) {
1703 if (resid[m] > 1.0) {
1704 double betat = 1.0 / resid[m];
1709 if (resid[m] < -1.0) {
1710 double betat = -1.0 / resid[m];
1717 if (ChemEquil_print_lvl > 0) {
1719 writelogf(
"(it %d) Beta = %g\n", iter, beta);
1728 for (m = 0; m <
m_mm; m++) {
1729 x[m] += beta * resid[m];
1731 n_t *= exp(beta * resid[m_mm]);
1735 if (ChemEquil_print_lvl > 0) {
1736 writelogf(
"(it %d) OLD_SOLUTION NEW SOLUTION (undamped updated)\n", iter);
1737 for (m = 0; m <
m_mm; m++) {
1738 string eee = eNames[m];
1739 writelogf(
" %5s %10.5g %10.5g %10.5g\n", eee.c_str(), x_old[m], x[m], resid[m]);
1741 writelogf(
" n_t %10.5g %10.5g %10.5g \n", x_old[m_mm], n_t, exp(resid[m_mm]));
1747 if (ChemEquil_print_lvl > 0) {
1752 writelogf(
" ChemEquil::estimateEP_Brinkley() SUCCESS: equilibrium found at T = %g, Pres = %g\n",
1755 writelogf(
" ChemEquil::estimateEP_Brinkley() FAILURE: equilibrium not found at T = %g, Pres = %g\n",
1769 if (fabs(elMolesGoal[
m_eloc]) > 1.0E-20) {
1776 int maxPosEloc = -1;
1777 int maxNegEloc = -1;
1778 double maxPosVal = -1.0;
1779 double maxNegVal = -1.0;
1780 if (ChemEquil_print_lvl > 0) {
1781 for (k = 0; k <
m_kk; k++) {
1782 if (
nAtoms(k,m_eloc) > 0.0) {
1788 if (
nAtoms(k,m_eloc) < 0.0) {
1798 double sumPos = 0.0;
1799 double sumNeg = 0.0;
1800 for (k = 0; k <
m_kk; k++) {
1801 if (
nAtoms(k,m_eloc) > 0.0) {
1804 if (
nAtoms(k,m_eloc) < 0.0) {
1810 if (sumPos >= sumNeg) {
1811 if (sumPos <= 0.0) {
1814 double factor = (elMolesGoal[
m_eloc] + sumNeg) / sumPos;
1816 if (ChemEquil_print_lvl > 0) {
1817 if (factor < 0.9999999999) {
1819 writelogf(
"adjustEloc: adjusted %s and friends from %g to %g to ensure neutrality condition\n",
1825 for (k = 0; k <
m_kk; k++) {
1826 if (
nAtoms(k,m_eloc) > 0.0) {
1831 double factor = (-elMolesGoal[
m_eloc] + sumPos) / sumNeg;
1833 if (ChemEquil_print_lvl > 0) {
1834 if (factor < 0.9999999999) {
1836 writelogf(
"adjustEloc: adjusted %s and friends from %g to %g to ensure neutrality condition\n",
1842 for (k = 0; k <
m_kk; k++) {
1843 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].
void beginLogGroup(const std::string &title, int loglevel)
Create a new group for log messages.
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.
This file contains definitions of terms that are used in internal routines and are unlikely to need m...
void initialize(thermo_t &s)
size_t m_nComponents
This is equal to the rank of the stoichiometric coefficient matrix when it is computed.
int solve(DenseMatrix &A, double *b)
Solve Ax = b. Array b is overwritten on exit with x.
This file contains definitions for utility functions and text for modules, inputfiles, logs, textlogs, HTML_logs (see Input File Handling, Diagnostic Output, Writing messages to the screen and Writing HTML Logfiles).
void getMoleFractions(doublereal *const x) const
Get the species mole fraction vector.
Headers for the MultiPhase object that is used to set up multiphase equilibrium problems (see Equilib...
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.
bool getElementPotentials(doublereal *lambda) const
Returns the element potentials stored in the ThermoPhase object.
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.
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.
void setElementPotentials(const vector_fp &lambda)
Stores the element potentials in the ThermoPhase object.
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...
const std::vector< std::string > & elementNames() const
Return a read-only reference to the vector of element names.
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.
void endLogGroup(const std::string &title)
Close the current group of log messages.
size_t nSpecies() const
Returns the number of species in the phase.
void addLogEntry(const std::string &tag, const std::string &value)
Add an entry to an HTML log file.
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.
Templates for operations on vector-like objects.
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.
Headers for the DenseMatrix object, which deals with dense rectangular matrices and description of th...
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...
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
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...
virtual void setToEquilState(const doublereal *lambda_RT)
This method is used by the ChemEquil equilibrium solver.
std::string speciesName(size_t k) const
Name of the species with index k.
Definitions for the classes that are thrown when Cantera experiences an error condition (also contain...
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.