std::string MolarityIonicVPSSTP::report(bool show_thermo, doublereal threshold) const { fmt::MemoryWriter b; try { if (name() != "") { b.write("\n {}:\n", name()); } b.write("\n"); b.write(" temperature {:12.6g} K\n", temperature()); b.write(" pressure {:12.6g} Pa\n", pressure()); b.write(" density {:12.6g} kg/m^3\n", density()); b.write(" mean mol. weight {:12.6g} amu\n", meanMolecularWeight()); doublereal phi = electricPotential(); b.write(" potential {:12.6g} V\n", phi); vector_fp x(m_kk); vector_fp molal(m_kk); vector_fp mu(m_kk); vector_fp muss(m_kk); vector_fp acMolal(m_kk); vector_fp actMolal(m_kk); getMoleFractions(&x[0]); getChemPotentials(&mu[0]); getStandardChemPotentials(&muss[0]); getActivities(&actMolal[0]); if (show_thermo) { b.write("\n"); b.write(" 1 kg 1 kmol\n"); b.write(" ----------- ------------\n"); b.write(" enthalpy {:12.6g} {:12.4g} J\n", enthalpy_mass(), enthalpy_mole()); b.write(" internal energy {:12.6g} {:12.4g} J\n", intEnergy_mass(), intEnergy_mole()); b.write(" entropy {:12.6g} {:12.4g} J/K\n", entropy_mass(), entropy_mole()); b.write(" Gibbs function {:12.6g} {:12.4g} J\n", gibbs_mass(), gibbs_mole()); b.write(" heat capacity c_p {:12.6g} {:12.4g} J/K\n", cp_mass(), cp_mole()); try { b.write(" heat capacity c_v {:12.6g} {:12.4g} J/K\n", cv_mass(), cv_mole()); } catch (NotImplementedError& e) { b.write(" heat capacity c_v <not implemented>\n"); } } } catch (CanteraError& e) { return b.str() + e.what(); } return b.str(); }
void SingleSpeciesTP::setState_HP(doublereal h, doublereal p, doublereal tol) { doublereal dt; setPressure(p); for (int n = 0; n < 50; n++) { dt = clip((h - enthalpy_mass())/cp_mass(), -100.0, 100.0); setState_TP(temperature() + dt, p); if (fabs(dt) < tol) { return; } } throw CanteraError("setState_HP","no convergence. dt = " + fp2str(dt)); }
/* * Format a summary of the mixture state for output. */ void MolalityVPSSTP::reportCSV(std::ofstream& csvFile) const { csvFile.precision(3); int tabS = 15; int tabM = 30; int tabL = 40; try { if (name() != "") { csvFile << "\n"+name()+"\n\n"; } csvFile << setw(tabL) << "temperature (K) =" << setw(tabS) << temperature() << endl; csvFile << setw(tabL) << "pressure (Pa) =" << setw(tabS) << pressure() << endl; csvFile << setw(tabL) << "density (kg/m^3) =" << setw(tabS) << density() << endl; csvFile << setw(tabL) << "mean mol. weight (amu) =" << setw(tabS) << meanMolecularWeight() << endl; csvFile << setw(tabL) << "potential (V) =" << setw(tabS) << electricPotential() << endl; csvFile << endl; csvFile << setw(tabL) << "enthalpy (J/kg) = " << setw(tabS) << enthalpy_mass() << setw(tabL) << "enthalpy (J/kmol) = " << setw(tabS) << enthalpy_mole() << endl; csvFile << setw(tabL) << "internal E (J/kg) = " << setw(tabS) << intEnergy_mass() << setw(tabL) << "internal E (J/kmol) = " << setw(tabS) << intEnergy_mole() << endl; csvFile << setw(tabL) << "entropy (J/kg) = " << setw(tabS) << entropy_mass() << setw(tabL) << "entropy (J/kmol) = " << setw(tabS) << entropy_mole() << endl; csvFile << setw(tabL) << "Gibbs (J/kg) = " << setw(tabS) << gibbs_mass() << setw(tabL) << "Gibbs (J/kmol) = " << setw(tabS) << gibbs_mole() << endl; csvFile << setw(tabL) << "heat capacity c_p (J/K/kg) = " << setw(tabS) << cp_mass() << setw(tabL) << "heat capacity c_p (J/K/kmol) = " << setw(tabS) << cp_mole() << endl; csvFile << setw(tabL) << "heat capacity c_v (J/K/kg) = " << setw(tabS) << cv_mass() << setw(tabL) << "heat capacity c_v (J/K/kmol) = " << setw(tabS) << cv_mole() << endl; csvFile.precision(8); vector<std::string> pNames; vector<vector_fp> data; vector_fp temp(nSpecies()); getMoleFractions(&temp[0]); pNames.push_back("X"); data.push_back(temp); try { getMolalities(&temp[0]); pNames.push_back("Molal"); data.push_back(temp); } catch (CanteraError& err) { err.save(); } try { getChemPotentials(&temp[0]); pNames.push_back("Chem. Pot. (J/kmol)"); data.push_back(temp); } catch (CanteraError& err) { err.save(); } try { getStandardChemPotentials(&temp[0]); pNames.push_back("Chem. Pot. SS (J/kmol)"); data.push_back(temp); } catch (CanteraError& err) { err.save(); } try { getMolalityActivityCoefficients(&temp[0]); pNames.push_back("Molal Act. Coeff."); data.push_back(temp); } catch (CanteraError& err) { err.save(); } try { getActivities(&temp[0]); pNames.push_back("Molal Activity"); data.push_back(temp); size_t iHp = speciesIndex("H+"); if (iHp != npos) { double pH = -log(temp[iHp]) / log(10.0); csvFile << setw(tabL) << "pH = " << setw(tabS) << pH << endl; } } catch (CanteraError& err) { err.save(); } try { getPartialMolarEnthalpies(&temp[0]); pNames.push_back("Part. Mol Enthalpy (J/kmol)"); data.push_back(temp); } catch (CanteraError& err) { err.save(); } try { getPartialMolarEntropies(&temp[0]); pNames.push_back("Part. Mol. Entropy (J/K/kmol)"); data.push_back(temp); } catch (CanteraError& err) { err.save(); } try { getPartialMolarIntEnergies(&temp[0]); pNames.push_back("Part. Mol. Energy (J/kmol)"); data.push_back(temp); } catch (CanteraError& err) { err.save(); } try { getPartialMolarCp(&temp[0]); pNames.push_back("Part. Mol. Cp (J/K/kmol"); data.push_back(temp); } catch (CanteraError& err) { err.save(); } try { getPartialMolarVolumes(&temp[0]); pNames.push_back("Part. Mol. Cv (J/K/kmol)"); data.push_back(temp); } catch (CanteraError& err) { err.save(); } csvFile << endl << setw(tabS) << "Species,"; for (size_t i = 0; i < pNames.size(); i++) { csvFile << setw(tabM) << pNames[i] << ","; } csvFile << endl; /* csvFile.fill('-'); csvFile << setw(tabS+(tabM+1)*pNames.size()) << "-\n"; csvFile.fill(' '); */ for (size_t k = 0; k < nSpecies(); k++) { csvFile << setw(tabS) << speciesName(k) + ","; if (data[0][k] > SmallNumber) { for (size_t i = 0; i < pNames.size(); i++) { csvFile << setw(tabM) << data[i][k] << ","; } csvFile << endl; } else { for (size_t i = 0; i < pNames.size(); i++) { csvFile << setw(tabM) << 0 << ","; } csvFile << endl; } } } catch (CanteraError& err) { err.save(); } }
/** * Format a summary of the mixture state for output. */ std::string MolalityVPSSTP::report(bool show_thermo) const { char p[800]; string s = ""; try { if (name() != "") { sprintf(p, " \n %s:\n", name().c_str()); s += p; } sprintf(p, " \n temperature %12.6g K\n", temperature()); s += p; sprintf(p, " pressure %12.6g Pa\n", pressure()); s += p; sprintf(p, " density %12.6g kg/m^3\n", density()); s += p; sprintf(p, " mean mol. weight %12.6g amu\n", meanMolecularWeight()); s += p; doublereal phi = electricPotential(); sprintf(p, " potential %12.6g V\n", phi); s += p; size_t kk = nSpecies(); vector_fp x(kk); vector_fp molal(kk); vector_fp mu(kk); vector_fp muss(kk); vector_fp acMolal(kk); vector_fp actMolal(kk); getMoleFractions(&x[0]); getMolalities(&molal[0]); getChemPotentials(&mu[0]); getStandardChemPotentials(&muss[0]); getMolalityActivityCoefficients(&acMolal[0]); getActivities(&actMolal[0]); size_t iHp = speciesIndex("H+"); if (iHp != npos) { double pH = -log(actMolal[iHp]) / log(10.0); sprintf(p, " pH %12.4g \n", pH); s += p; } if (show_thermo) { sprintf(p, " \n"); s += p; sprintf(p, " 1 kg 1 kmol\n"); s += p; sprintf(p, " ----------- ------------\n"); s += p; sprintf(p, " enthalpy %12.6g %12.4g J\n", enthalpy_mass(), enthalpy_mole()); s += p; sprintf(p, " internal energy %12.6g %12.4g J\n", intEnergy_mass(), intEnergy_mole()); s += p; sprintf(p, " entropy %12.6g %12.4g J/K\n", entropy_mass(), entropy_mole()); s += p; sprintf(p, " Gibbs function %12.6g %12.4g J\n", gibbs_mass(), gibbs_mole()); s += p; sprintf(p, " heat capacity c_p %12.6g %12.4g J/K\n", cp_mass(), cp_mole()); s += p; try { sprintf(p, " heat capacity c_v %12.6g %12.4g J/K\n", cv_mass(), cv_mole()); s += p; } catch (CanteraError& err) { err.save(); sprintf(p, " heat capacity c_v <not implemented> \n"); s += p; } } sprintf(p, " \n"); s += p; if (show_thermo) { sprintf(p, " X " " Molalities Chem.Pot. ChemPotSS ActCoeffMolal\n"); s += p; sprintf(p, " " " (J/kmol) (J/kmol) \n"); s += p; sprintf(p, " ------------- " " ------------ ------------ ------------ ------------\n"); s += p; for (size_t k = 0; k < kk; k++) { if (x[k] > SmallNumber) { sprintf(p, "%18s %12.6g %12.6g %12.6g %12.6g %12.6g\n", speciesName(k).c_str(), x[k], molal[k], mu[k], muss[k], acMolal[k]); } else { sprintf(p, "%18s %12.6g %12.6g N/A %12.6g %12.6g \n", speciesName(k).c_str(), x[k], molal[k], muss[k], acMolal[k]); } s += p; } } else { sprintf(p, " X" "Molalities\n"); s += p; sprintf(p, " -------------" " ------------\n"); s += p; for (size_t k = 0; k < kk; k++) { sprintf(p, "%18s %12.6g %12.6g\n", speciesName(k).c_str(), x[k], molal[k]); s += p; } } } catch (CanteraError& err) { err.save(); } return s; }
std::string ThermoPhase::report(bool show_thermo, doublereal threshold) const { fmt::MemoryWriter b; try { if (name() != "") { b.write("\n {}:\n", name()); } b.write("\n"); b.write(" temperature {:12.6g} K\n", temperature()); b.write(" pressure {:12.6g} Pa\n", pressure()); b.write(" density {:12.6g} kg/m^3\n", density()); b.write(" mean mol. weight {:12.6g} amu\n", meanMolecularWeight()); doublereal phi = electricPotential(); if (phi != 0.0) { b.write(" potential {:12.6g} V\n", phi); } if (show_thermo) { b.write("\n"); b.write(" 1 kg 1 kmol\n"); b.write(" ----------- ------------\n"); b.write(" enthalpy {:12.5g} {:12.4g} J\n", enthalpy_mass(), enthalpy_mole()); b.write(" internal energy {:12.5g} {:12.4g} J\n", intEnergy_mass(), intEnergy_mole()); b.write(" entropy {:12.5g} {:12.4g} J/K\n", entropy_mass(), entropy_mole()); b.write(" Gibbs function {:12.5g} {:12.4g} J\n", gibbs_mass(), gibbs_mole()); b.write(" heat capacity c_p {:12.5g} {:12.4g} J/K\n", cp_mass(), cp_mole()); try { b.write(" heat capacity c_v {:12.5g} {:12.4g} J/K\n", cv_mass(), cv_mole()); } catch (NotImplementedError&) { b.write(" heat capacity c_v <not implemented> \n"); } } vector_fp x(m_kk); vector_fp y(m_kk); vector_fp mu(m_kk); getMoleFractions(&x[0]); getMassFractions(&y[0]); getChemPotentials(&mu[0]); int nMinor = 0; doublereal xMinor = 0.0; doublereal yMinor = 0.0; b.write("\n"); if (show_thermo) { b.write(" X " " Y Chem. Pot. / RT\n"); b.write(" ------------- " "------------ ------------\n"); for (size_t k = 0; k < m_kk; k++) { if (abs(x[k]) >= threshold) { if (abs(x[k]) > SmallNumber) { b.write("{:>18s} {:12.6g} {:12.6g} {:12.6g}\n", speciesName(k), x[k], y[k], mu[k]/RT()); } else { b.write("{:>18s} {:12.6g} {:12.6g}\n", speciesName(k), x[k], y[k]); } } else { nMinor++; xMinor += x[k]; yMinor += y[k]; } } } else { b.write(" X Y\n"); b.write(" ------------- ------------\n"); for (size_t k = 0; k < m_kk; k++) { if (abs(x[k]) >= threshold) { b.write("{:>18s} {:12.6g} {:12.6g}\n", speciesName(k), x[k], y[k]); } else { nMinor++; xMinor += x[k]; yMinor += y[k]; } } } if (nMinor) { b.write(" [{:+5d} minor] {:12.6g} {:12.6g}\n", nMinor, xMinor, yMinor); } } catch (CanteraError& err) { return b.str() + err.what(); } return b.str(); }
void ThermoPhase::setState_HPorUV(doublereal Htarget, doublereal p, doublereal dTtol, bool doUV) { doublereal dt; doublereal v = 0.0; // Assign the specific volume or pressure and make sure it's positive if (doUV) { doublereal v = p; if (v < 1.0E-300) { throw CanteraError("setState_HPorUV (UV)", "Input specific volume is too small or negative. v = {}", v); } setDensity(1.0/v); } else { if (p < 1.0E-300) { throw CanteraError("setState_HPorUV (HP)", "Input pressure is too small or negative. p = {}", p); } setPressure(p); } double Tmax = maxTemp() + 0.1; double Tmin = minTemp() - 0.1; // Make sure we are within the temperature bounds at the start // of the iteration double Tnew = temperature(); double Tinit = Tnew; if (Tnew > Tmax) { Tnew = Tmax - 1.0; } else if (Tnew < Tmin) { Tnew = Tmin + 1.0; } if (Tnew != Tinit) { setState_conditional_TP(Tnew, p, !doUV); } double Hnew = (doUV) ? intEnergy_mass() : enthalpy_mass(); double Cpnew = (doUV) ? cv_mass() : cp_mass(); double Htop = Hnew; double Ttop = Tnew; double Hbot = Hnew; double Tbot = Tnew; bool ignoreBounds = false; // Unstable phases are those for which cp < 0.0. These are possible for // cases where we have passed the spinodal curve. bool unstablePhase = false; // Counter indicating the last temperature point where the // phase was unstable double Tunstable = -1.0; bool unstablePhaseNew = false; // Newton iteration for (int n = 0; n < 500; n++) { double Told = Tnew; double Hold = Hnew; double cpd = Cpnew; if (cpd < 0.0) { unstablePhase = true; Tunstable = Tnew; } // limit step size to 100 K dt = clip((Htarget - Hold)/cpd, -100.0, 100.0); // Calculate the new T Tnew = Told + dt; // Limit the step size so that we are convergent This is the step that // makes it different from a Newton's algorithm if ((dt > 0.0 && unstablePhase) || (dt <= 0.0 && !unstablePhase)) { if (Hbot < Htarget && Tnew < (0.75 * Tbot + 0.25 * Told)) { dt = 0.75 * (Tbot - Told); Tnew = Told + dt; } } else if (Htop > Htarget && Tnew > (0.75 * Ttop + 0.25 * Told)) { dt = 0.75 * (Ttop - Told); Tnew = Told + dt; } // Check Max and Min values if (Tnew > Tmax && !ignoreBounds) { setState_conditional_TP(Tmax, p, !doUV); double Hmax = (doUV) ? intEnergy_mass() : enthalpy_mass(); if (Hmax >= Htarget) { if (Htop < Htarget) { Ttop = Tmax; Htop = Hmax; } } else { Tnew = Tmax + 1.0; ignoreBounds = true; } } if (Tnew < Tmin && !ignoreBounds) { setState_conditional_TP(Tmin, p, !doUV); double Hmin = (doUV) ? intEnergy_mass() : enthalpy_mass(); if (Hmin <= Htarget) { if (Hbot > Htarget) { Tbot = Tmin; Hbot = Hmin; } } else { Tnew = Tmin - 1.0; ignoreBounds = true; } } // Try to keep phase within its region of stability // -> Could do a lot better if I calculate the // spinodal value of H. for (int its = 0; its < 10; its++) { Tnew = Told + dt; if (Tnew < Told / 3.0) { Tnew = Told / 3.0; dt = -2.0 * Told / 3.0; } setState_conditional_TP(Tnew, p, !doUV); if (doUV) { Hnew = intEnergy_mass(); Cpnew = cv_mass(); } else { Hnew = enthalpy_mass(); Cpnew = cp_mass(); } if (Cpnew < 0.0) { unstablePhaseNew = true; Tunstable = Tnew; } else { unstablePhaseNew = false; break; } if (unstablePhase == false && unstablePhaseNew == true) { dt *= 0.25; } } if (Hnew == Htarget) { return; } else if (Hnew > Htarget && (Htop < Htarget || Hnew < Htop)) { Htop = Hnew; Ttop = Tnew; } else if (Hnew < Htarget && (Hbot > Htarget || Hnew > Hbot)) { Hbot = Hnew; Tbot = Tnew; } // Convergence in H double Herr = Htarget - Hnew; double acpd = std::max(fabs(cpd), 1.0E-5); double denom = std::max(fabs(Htarget), acpd * dTtol); double HConvErr = fabs((Herr)/denom); if (HConvErr < 0.00001 *dTtol || fabs(dt) < dTtol) { return; } } // We are here when there hasn't been convergence // Formulate a detailed error message, since questions seem to arise often // about the lack of convergence. string ErrString = "No convergence in 500 iterations\n"; if (doUV) { ErrString += fmt::format( "\tTarget Internal Energy = {}\n" "\tCurrent Specific Volume = {}\n" "\tStarting Temperature = {}\n" "\tCurrent Temperature = {}\n" "\tCurrent Internal Energy = {}\n" "\tCurrent Delta T = {}\n", Htarget, v, Tinit, Tnew, Hnew, dt); } else { ErrString += fmt::format( "\tTarget Enthalpy = {}\n" "\tCurrent Pressure = {}\n" "\tStarting Temperature = {}\n" "\tCurrent Temperature = {}\n" "\tCurrent Enthalpy = {}\n" "\tCurrent Delta T = {}\n", Htarget, p, Tinit, Tnew, Hnew, dt); } if (unstablePhase) { ErrString += fmt::format( "\t - The phase became unstable (Cp < 0) T_unstable_last = {}\n", Tunstable); } if (doUV) { throw CanteraError("setState_HPorUV (UV)", ErrString); } else { throw CanteraError("setState_HPorUV (HP)", ErrString); } }
std::string MolarityIonicVPSSTP::report(bool show_thermo) const { char p[800]; string s = ""; try { if (name() != "") { sprintf(p, " \n %s:\n", name().c_str()); s += p; } sprintf(p, " \n temperature %12.6g K\n", temperature()); s += p; sprintf(p, " pressure %12.6g Pa\n", pressure()); s += p; sprintf(p, " density %12.6g kg/m^3\n", density()); s += p; sprintf(p, " mean mol. weight %12.6g amu\n", meanMolecularWeight()); s += p; doublereal phi = electricPotential(); sprintf(p, " potential %12.6g V\n", phi); s += p; size_t kk = nSpecies(); vector_fp x(kk); vector_fp molal(kk); vector_fp mu(kk); vector_fp muss(kk); vector_fp acMolal(kk); vector_fp actMolal(kk); getMoleFractions(&x[0]); getChemPotentials(&mu[0]); getStandardChemPotentials(&muss[0]); getActivities(&actMolal[0]); if (show_thermo) { sprintf(p, " \n"); s += p; sprintf(p, " 1 kg 1 kmol\n"); s += p; sprintf(p, " ----------- ------------\n"); s += p; sprintf(p, " enthalpy %12.6g %12.4g J\n", enthalpy_mass(), enthalpy_mole()); s += p; sprintf(p, " internal energy %12.6g %12.4g J\n", intEnergy_mass(), intEnergy_mole()); s += p; sprintf(p, " entropy %12.6g %12.4g J/K\n", entropy_mass(), entropy_mole()); s += p; sprintf(p, " Gibbs function %12.6g %12.4g J\n", gibbs_mass(), gibbs_mole()); s += p; sprintf(p, " heat capacity c_p %12.6g %12.4g J/K\n", cp_mass(), cp_mole()); s += p; try { sprintf(p, " heat capacity c_v %12.6g %12.4g J/K\n", cv_mass(), cv_mole()); s += p; } catch (CanteraError& e) { e.save(); sprintf(p, " heat capacity c_v <not implemented> \n"); s += p; } } } catch (CanteraError& e) { e.save(); } return s; }
std::string MolalityVPSSTP::report(bool show_thermo, doublereal threshold) const { fmt::MemoryWriter b; try { if (name() != "") { b.write("\n {}:\n", name()); } b.write("\n"); b.write(" temperature {:12.6g} K\n", temperature()); b.write(" pressure {:12.6g} Pa\n", pressure()); b.write(" density {:12.6g} kg/m^3\n", density()); b.write(" mean mol. weight {:12.6g} amu\n", meanMolecularWeight()); doublereal phi = electricPotential(); b.write(" potential {:12.6g} V\n", phi); vector_fp x(m_kk); vector_fp molal(m_kk); vector_fp mu(m_kk); vector_fp muss(m_kk); vector_fp acMolal(m_kk); vector_fp actMolal(m_kk); getMoleFractions(&x[0]); getMolalities(&molal[0]); getChemPotentials(&mu[0]); getStandardChemPotentials(&muss[0]); getMolalityActivityCoefficients(&acMolal[0]); getActivities(&actMolal[0]); size_t iHp = speciesIndex("H+"); if (iHp != npos) { double pH = -log(actMolal[iHp]) / log(10.0); b.write(" pH {:12.4g}\n", pH); } if (show_thermo) { b.write("\n"); b.write(" 1 kg 1 kmol\n"); b.write(" ----------- ------------\n"); b.write(" enthalpy {:12.6g} {:12.4g} J\n", enthalpy_mass(), enthalpy_mole()); b.write(" internal energy {:12.6g} {:12.4g} J\n", intEnergy_mass(), intEnergy_mole()); b.write(" entropy {:12.6g} {:12.4g} J/K\n", entropy_mass(), entropy_mole()); b.write(" Gibbs function {:12.6g} {:12.4g} J\n", gibbs_mass(), gibbs_mole()); b.write(" heat capacity c_p {:12.6g} {:12.4g} J/K\n", cp_mass(), cp_mole()); try { b.write(" heat capacity c_v {:12.6g} {:12.4g} J/K\n", cv_mass(), cv_mole()); } catch (NotImplementedError& e) { b.write(" heat capacity c_v <not implemented>\n"); } } b.write("\n"); int nMinor = 0; doublereal xMinor = 0.0; if (show_thermo) { b.write(" X " " Molalities Chem.Pot. ChemPotSS ActCoeffMolal\n"); b.write(" " " (J/kmol) (J/kmol)\n"); b.write(" ------------- " " ------------ ------------ ------------ ------------\n"); for (size_t k = 0; k < m_kk; k++) { if (x[k] > threshold) { if (x[k] > SmallNumber) { b.write("{:>18s} {:12.6g} {:12.6g} {:12.6g} {:12.6g} {:12.6g}\n", speciesName(k), x[k], molal[k], mu[k], muss[k], acMolal[k]); } else { b.write("{:>18s} {:12.6g} {:12.6g} N/A {:12.6g} {:12.6g}\n", speciesName(k), x[k], molal[k], muss[k], acMolal[k]); } } else { nMinor++; xMinor += x[k]; } } } else { b.write(" X" "Molalities\n"); b.write(" -------------" " ------------\n"); for (size_t k = 0; k < m_kk; k++) { if (x[k] > threshold) { b.write("{:>18s} {:12.6g} {:12.6g}\n", speciesName(k), x[k], molal[k]); } else { nMinor++; xMinor += x[k]; } } } if (nMinor) { b.write(" [{:+5d} minor] {:12.6g}\n", nMinor, xMinor); } } catch (CanteraError& err) { return b.str() + err.what(); } return b.str(); }