15 #include "vcs_species_thermo.h"
16 #include "vcs_SpeciesProperties.h"
21 #include "cantera/thermo/mix_defs.h"
33 using namespace Cantera;
41 vcs_MultiPhaseEquil::vcs_MultiPhaseEquil() :
86 int printLvl, doublereal err,
87 int maxsteps,
int loglevel)
94 if ((XY != TV) && (XY != HV) && (XY != UV) && (XY != SV)) {
95 throw CanteraError(
"vcs_MultiPhaseEquil::equilibrate_TV",
96 "Wrong XY flag:" +
int2str(XY));
106 int strt = estimateEquil;
113 doublereal Vnow, Verr;
114 int printLvlSub =
std::max(0, printLvl - 1);
115 for (
int n = 0; n < maxiter; n++) {
121 iSuccess =
equilibrate_TP(strt, printLvlSub, err, maxsteps, loglevel);
126 printLvlSub, err, maxsteps, loglevel);
131 printLvlSub, err, maxsteps, loglevel);
136 printLvlSub, err, maxsteps, loglevel);
156 Verr = fabs((Vtarget - Vnow)/Vtarget);
169 dVdP = (V2 - V1) / (P2 - P1);
174 Pnew = Pnow + (Vtarget - Vnow) / dVdP;
175 if (Pnew < 0.2 * Pnow) {
178 if (Pnew > 3.0 * Pnow) {
186 Pnew = Pnow + 0.5*(Vtarget - Vnow)/dVdP;
187 if (Pnew < 0.5* Pnow) {
190 if (Pnew > 1.7 * Pnow) {
198 "No convergence for V");
207 int XY,
double Tlow,
double Thigh,
209 int printLvl, doublereal err,
210 int maxsteps,
int loglevel)
214 if (XY != HP && XY != UP) {
215 throw CanteraError(
"vcs_MultiPhaseEquil::equilibrate_HP",
218 int strt = estimateEquil;
225 if (Thigh <= 0.0 || Thigh > 1.0E6) {
231 doublereal cpb = 1.0, dT, dTa, dTmax, Tnew;
233 doublereal Hlow =
Undef;
234 doublereal Hhigh =
Undef;
235 doublereal Herr, HConvErr;
237 int printLvlSub =
std::max(printLvl - 1, 0);
239 for (
int n = 0; n < maxiter; n++) {
248 iSuccess =
equilibrate_TP(strt, printLvlSub, err, maxsteps, loglevel);
257 double Tmoles = pmoles[0];
258 double HperMole = Hnow/Tmoles;
260 plogf(
"T = %g, Hnow = %g ,Tmoles = %g, HperMole = %g",
261 Tnow, Hnow, Tmoles, HperMole);
270 if (Hnow < Htarget) {
285 cpb = (Hhigh - Hlow)/(Thigh - Tlow);
286 dT = (Htarget - Hnow)/cpb;
288 dTmax = 0.5*fabs(Thigh - Tlow);
293 Tnew = sqrt(Tlow*Thigh);
302 double acpb =
std::max(fabs(cpb), 1.0E-6);
303 double denom =
std::max(fabs(Htarget), acpb);
304 Herr = Htarget - Hnow;
305 HConvErr = fabs((Herr)/denom);
314 plogf(
" equilibrate_HP: It = %d, Tcurr = %g Hcurr = %g, Htarget = %g\n",
315 n, Tnow, Hnow, Htarget);
316 plogf(
" H rel error = %g, cp = %g, HConvErr = %g\n",
317 Herr, cpb, HConvErr);
320 if (HConvErr < err) {
325 plogf(
" equilibrate_HP: CONVERGENCE: Hfinal = %g Tfinal = %g, Its = %d \n",
327 plogf(
" H rel error = %g, cp = %g, HConvErr = %g\n",
328 Herr, cpb, HConvErr);
339 if (!estimateEquil) {
341 "try estimating composition at the start");
344 Tnew = 0.5*(Tnow + Thigh);
345 if (fabs(Tnew - Tnow) < 1.0) {
350 "trying T = "+
fp2str(Tnow));
359 "No convergence for T");
366 double Tlow,
double Thigh,
368 int printLvl, doublereal err,
369 int maxsteps,
int loglevel)
372 int strt = estimateEquil;
379 if (Thigh <= 0.0 || Thigh > 1.0E6) {
385 doublereal cpb = 1.0, dT, dTa, dTmax, Tnew;
387 doublereal Slow =
Undef;
388 doublereal Shigh =
Undef;
389 doublereal Serr, SConvErr;
397 int printLvlSub =
std::max(printLvl - 1, 0);
399 for (
int n = 0; n < maxiter; n++) {
407 int iSuccess =
equilibrate_TP(strt, printLvlSub, err, maxsteps, loglevel);
412 double Tmoles = pmoles[0];
413 double SperMole = Snow/Tmoles;
414 plogf(
"T = %g, Snow = %g ,Tmoles = %g, SperMole = %g\n",
415 Tnow, Snow, Tmoles, SperMole);
421 if (Snow < Starget) {
426 if (Slow > Starget) {
445 cpb = (Shigh - Slow)/(Thigh - Tlow);
446 dT = (Starget - Snow)/cpb;
449 dTmax = 0.5*fabs(Thigh - Tlow);
450 if (Tnew > Thigh || Tnew < Tlow) {
451 dTmax = 1.5*fabs(Thigh - Tlow);
458 Tnew = sqrt(Tlow*Thigh);
462 double acpb =
std::max(fabs(cpb), 1.0E-6);
463 double denom =
std::max(fabs(Starget), acpb);
464 Serr = Starget - Snow;
465 SConvErr = fabs((Serr)/denom);
474 plogf(
" equilibrate_SP: It = %d, Tcurr = %g Scurr = %g, Starget = %g\n",
475 n, Tnow, Snow, Starget);
476 plogf(
" S rel error = %g, cp = %g, SConvErr = %g\n",
477 Serr, cpb, SConvErr);
480 if (SConvErr < err) {
485 plogf(
" equilibrate_SP: CONVERGENCE: Sfinal = %g Tfinal = %g, Its = %d \n",
487 plogf(
" S rel error = %g, cp = %g, HConvErr = %g\n",
488 Serr, cpb, SConvErr);
499 if (!estimateEquil) {
501 "try estimating composition at the start");
504 Tnew = 0.5*(Tnow + Thigh);
505 if (fabs(Tnew - Tnow) < 1.0) {
510 "trying T = "+
fp2str(Tnow));
519 "No convergence for T");
527 int printLvl, doublereal err,
528 int maxsteps,
int loglevel)
533 iSuccess =
equilibrate_TP(estimateEquil, printLvl, err, maxsteps, loglevel);
534 }
else if (XY == HP || XY == UP) {
543 estimateEquil, printLvl, err, maxsteps, loglevel);
544 }
else if (XY == SP) {
549 estimateEquil, printLvl, err, maxsteps, loglevel);
551 }
else if (XY == TV) {
554 estimateEquil, printLvl, err, maxsteps, loglevel);
555 }
else if (XY == HV) {
558 estimateEquil, printLvl, err, maxsteps, loglevel);
559 }
else if (XY == UV) {
562 estimateEquil, printLvl, err, maxsteps, loglevel);
563 }
else if (XY == SV) {
566 printLvl, err, maxsteps, loglevel);
569 "Unsupported Option");
578 int printLvl, doublereal err,
579 int maxsteps,
int loglevel)
583 int maxit = maxsteps;
619 "Temperature less than zero on input");
624 "Pressure less than zero on input");
627 beginLogGroup(
"vcs_MultiPhaseEquil::equilibrate_TP", loglevel);
665 double phaseMole = 0.0;
667 for (
size_t k = 0; k < tref.
nSpecies(); k++, kGlob++) {
676 plogf(
"\n Results from vcs:\n");
678 plogf(
"\nVCS FAILED TO CONVERGE!\n");
684 plogf(
"----------------------------------------"
685 "---------------------\n");
686 plogf(
" Name Mole_Number");
692 plogf(
" Mole_Fraction Chem_Potential");
694 plogf(
" (kcal/mol)\n");
696 plogf(
" (Dimensionless)\n");
698 plogf(
" (kJ/mol)\n");
700 plogf(
" (Kelvin)\n");
702 plogf(
" (J/kmol)\n");
704 plogf(
"--------------------------------------------------"
717 plogf(
" -1.000e+300\n");
726 plogf(
"------------------------------------------"
727 "-------------------\n");
730 plogf(
"Total time = %12.6e seconds\n", te);
756 FILE* FP = fopen(reportFile.c_str(),
"w");
758 plogf(
"Failure to open file\n");
767 std::vector<double> VolPM;
768 std::vector<double> activity;
769 std::vector<double> ac;
770 std::vector<double> mu;
771 std::vector<double> mu0;
772 std::vector<double> molalities;
776 for (
size_t iphase = 0; iphase < nphase; iphase++) {
780 VolPM.resize(nSpecies, 0.0);
785 double VolPhaseVolumes = 0.0;
786 for (k = 0; k < nSpecies; k++) {
787 VolPhaseVolumes += VolPM[k] * mf[istart + k];
789 VolPhaseVolumes *= TMolesPhase;
790 vol += VolPhaseVolumes;
793 fprintf(FP,
"--------------------- VCS_MULTIPHASE_EQUIL FINAL REPORT"
794 " -----------------------------\n");
795 fprintf(FP,
"Temperature = %11.5g kelvin\n", Temp);
796 fprintf(FP,
"Pressure = %11.5g Pascal\n", pres);
797 fprintf(FP,
"Total Volume = %11.5g m**3\n", vol);
801 for (
size_t iphase = 0; iphase < nphase; iphase++) {
805 string phaseName = tref.
name();
810 activity.resize(nSpecies, 0.0);
811 ac.resize(nSpecies, 0.0);
813 mu0.resize(nSpecies, 0.0);
814 mu.resize(nSpecies, 0.0);
815 VolPM.resize(nSpecies, 0.0);
816 molalities.resize(nSpecies, 0.0);
825 double VolPhaseVolumes = 0.0;
826 for (k = 0; k < nSpecies; k++) {
827 VolPhaseVolumes += VolPM[k] * mf[istart + k];
829 VolPhaseVolumes *= TMolesPhase;
830 vol += VolPhaseVolumes;
833 if (actConvention == 1) {
839 fprintf(FP,
" Name, Phase, PhaseMoles, Mole_Fract, "
840 "Molalities, ActCoeff, Activity,"
841 "ChemPot_SS0, ChemPot, mole_num, PMVol, Phase_Volume\n");
843 fprintf(FP,
" , , (kmol), , "
845 " (J/kmol), (J/kmol), (kmol), (m**3/kmol), (m**3)\n");
847 for (k = 0; k < nSpecies; k++) {
849 fprintf(FP,
"%12s, %11s, %11.3e, %11.3e, %11.3e, %11.3e, %11.3e,"
850 "%11.3e, %11.3e, %11.3e, %11.3e, %11.3e\n",
852 phaseName.c_str(), TMolesPhase,
853 mf[istart + k], molalities[k], ac[k], activity[k],
854 mu0[k]*1.0E-6, mu[k]*1.0E-6,
855 mf[istart + k] * TMolesPhase,
856 VolPM[k], VolPhaseVolumes);
861 fprintf(FP,
" Name, Phase, PhaseMoles, Mole_Fract, "
862 "Molalities, ActCoeff, Activity,"
863 " ChemPotSS0, ChemPot, mole_num, PMVol, Phase_Volume\n");
865 fprintf(FP,
" , , (kmol), , "
867 " (J/kmol), (J/kmol), (kmol), (m**3/kmol), (m**3)\n");
869 for (k = 0; k < nSpecies; k++) {
872 for (k = 0; k < nSpecies; k++) {
874 fprintf(FP,
"%12s, %11s, %11.3e, %11.3e, %11.3e, %11.3e, %11.3e, "
875 "%11.3e, %11.3e,% 11.3e, %11.3e, %11.3e\n",
877 phaseName.c_str(), TMolesPhase,
878 mf[istart + k], molalities[k], ac[k],
879 activity[k], mu0[k]*1.0E-6, mu[k]*1.0E-6,
880 mf[istart + k] * TMolesPhase,
881 VolPM[k], VolPhaseVolumes);
890 for (k = 0; k < nSpecies; k++) {
891 if (!vcs_doubleEqual(fe[istart+k], mu[k])) {
892 fprintf(FP,
"ERROR: incompatibility!\n");
894 plogf(
"ERROR: incompatibility!\n");
909 static void print_char(
const char letter,
const int num)
911 for (
int i = 0; i < num; i++) {
925 VCS_SPECIES_THERMO* ts_ptr = 0;
930 size_t totNumPhases = mphase->
nPhases();
931 size_t totNumSpecies = mphase->
nSpecies();
937 vprob->
NPhase = totNumPhases;
945 vprob->Title =
"MultiPhase Object";
956 for (
size_t iphase = 0; iphase < totNumPhases; iphase++) {
961 tPhase = &(mphase->
phase(iphase));
978 size_t nSpPhase = tPhase->
nSpecies();
982 string phaseName = tPhase->
name();
995 VolPhase->
resize(iphase, nSpPhase, nelem, phaseName.c_str(), 0.0);
1021 case cIncompressible:
1025 plogf(
"cSurf not handled yet\n");
1027 case cStoichSubstance:
1032 plogf(
"cPureFluid not recognized yet by VCSnonideal\n");
1036 plogf(
"cEdge not handled yet\n");
1038 case cIdealSolidSolnPhase0:
1039 case cIdealSolidSolnPhase1:
1040 case cIdealSolidSolnPhase2:
1045 plogf(
"Unknown Cantera EOS to VCSnonideal: %d\n", eos);
1049 plogf(
"vcs functions asked for, but unimplemented\n");
1074 vector<double> muPhase(tPhase->
nSpecies(),0.0);
1076 double tMoles = 0.0;
1080 for (
size_t k = 0; k < nSpPhase; k++) {
1102 vprob->
SpName[kT] = stmp;
1110 tMoles += vprob->
w[kT];
1138 sProp->NumElements = vprob->
ne;
1139 sProp->SpName = vprob->
SpName[kT];
1140 sProp->SpeciesThermo = ts_ptr;
1142 sProp->FormulaMatrixCol.resize(vprob->
ne, 0.0);
1143 for (
size_t e = 0; e < vprob->
ne; e++) {
1146 sProp->Charge = tPhase->
charge(k);
1147 sProp->SurfaceSpecies =
false;
1159 ts_ptr->IndexPhase = iphase;
1160 ts_ptr->IndexSpeciesPhase = k;
1161 ts_ptr->OwningPhase = VolPhase;
1169 double minTemp, maxTemp, refPressure;
1170 sp.
reportParams(k, spType, c, minTemp, maxTemp, refPressure);
1173 ts_ptr->SS0_Model = VCS_SS0_CONSTANT;
1174 ts_ptr->SS0_T0 = c[0];
1175 ts_ptr->SS0_H0 = c[1];
1176 ts_ptr->SS0_S0 = c[2];
1177 ts_ptr->SS0_Cp0 = c[3];
1179 ts_ptr->SSStar_Model = VCS_SSSTAR_IDEAL_GAS;
1180 ts_ptr->SSStar_Vol_Model = VCS_SSVOL_IDEALGAS;
1182 ts_ptr->SSStar_Model = VCS_SSSTAR_CONSTANT;
1183 ts_ptr->SSStar_Vol_Model = VCS_SSVOL_CONSTANT;
1185 ts_ptr->Activity_Coeff_Model = VCS_AC_CONSTANT;
1186 ts_ptr->Activity_Coeff_Params = NULL;
1189 plogf(
"vcs_Cantera_convert: Species Type %d not known \n",
1192 ts_ptr->SS0_Model = VCS_SS0_NOTHANDLED;
1193 ts_ptr->SSStar_Model = VCS_SSSTAR_NOTHANDLED;
1194 if (!(ts_ptr->UseCanteraCalls)) {
1195 plogf(
"Cantera calls not being used -> exiting\n");
1204 ts_ptr->SSStar_Vol_Model = VCS_SSVOL_IDEALGAS;
1205 ts_ptr->SSStar_Vol_Params = NULL;
1206 ts_ptr->SSStar_Vol0 = 82.05 * 273.15 / 1.0;
1209 std::vector<double> phaseTermCoeff(nSpPhase, 0.0);
1212 ts_ptr->SSStar_Vol_Model = VCS_SSVOL_CONSTANT;
1213 ts_ptr->SSStar_Vol0 = phaseTermCoeff[k];
1224 for (
size_t k = 0; k < nSpPhase; k++) {
1226 vprob->
mf[kTa] = vprob->
w[kTa] / tMoles;
1233 for (
size_t k = 0; k < nSpPhase; k++) {
1235 vprob->
mf[kTa]= 1.0 / (double) nSpPhase;
1245 for (
size_t k = 0; k < nSpPhase; k++) {
1247 ts_ptr = sProp->SpeciesThermo;
1249 ts_ptr->SS0_TSave = vprob->
T;
1259 vprob->
gai.resize(vprob->
ne, 0.0);
1267 print_char(
'=', 80);
1269 print_char(
'=', 16);
1270 plogf(
" Cantera_to_vprob: START OF PROBLEM STATEMENT ");
1271 print_char(
'=', 20);
1273 print_char(
'=', 80);
1275 plogf(
" Phase IDs of species\n");
1276 plogf(
" species phaseID phaseName ");
1277 plogf(
" Initial_Estimated_kMols\n");
1278 for (
size_t i = 0; i < vprob->
nspecies; i++) {
1279 size_t iphase = vprob->
PhaseID[i];
1282 plogf(
"%16s %5d %16s", vprob->
SpName[i].c_str(), iphase,
1284 plogf(
" %-10.5g\n", vprob->
w[i]);
1291 print_char(
'-', 80);
1293 plogf(
" Information about phases\n");
1294 plogf(
" PhaseName PhaseNum SingSpec GasPhase EqnState NumSpec");
1295 plogf(
" TMolesInert Tmoles(kmol)\n");
1297 for (
size_t iphase = 0; iphase < vprob->
NPhase; iphase++) {
1299 std::string sEOS = string16_EOSType(VolPhase->
m_eqnState);
1300 plogf(
"%16s %5d %5d %8d %16s %8d %16e ", VolPhase->
PhaseName.c_str(),
1308 print_char(
'=', 80);
1310 print_char(
'=', 16);
1311 plogf(
" Cantera_to_vprob: END OF PROBLEM STATEMENT ");
1312 print_char(
'=', 20);
1314 print_char(
'=', 80);
1328 size_t totNumPhases = mphase->
nPhases();
1330 std::vector<double> tmpMoles;
1341 for (
size_t iphase = 0; iphase < totNumPhases; iphase++) {
1342 tPhase = &(mphase->
phase(iphase));
1351 vector<double> muPhase(tPhase->
nSpecies(),0.0);
1356 size_t nSpPhase = tPhase->
nSpecies();
1358 tmpMoles.resize(nSpPhase);
1359 for (
size_t k = 0; k < nSpPhase; k++) {
1377 if ((nSpPhase == 1) && (volPhase->
phiVarIndex() == 0)) {
1400 print_char(
'=', 80);
1402 print_char(
'=', 20);
1403 plogf(
" Cantera_to_vprob: START OF PROBLEM STATEMENT ");
1404 print_char(
'=', 20);
1406 print_char(
'=', 80);
1408 plogf(
" Phase IDs of species\n");
1409 plogf(
" species phaseID phaseName ");
1410 plogf(
" Initial_Estimated_kMols\n");
1411 for (
size_t i = 0; i < vprob->
nspecies; i++) {
1412 size_t iphase = vprob->
PhaseID[i];
1415 plogf(
"%16s %5d %16s", vprob->
SpName[i].c_str(), iphase,
1417 plogf(
" %-10.5g\n", vprob->
w[i]);
1424 print_char(
'-', 80);
1426 plogf(
" Information about phases\n");
1427 plogf(
" PhaseName PhaseNum SingSpec GasPhase EqnState NumSpec");
1428 plogf(
" TMolesInert Tmoles(kmol)\n");
1430 for (
size_t iphase = 0; iphase < vprob->
NPhase; iphase++) {
1432 std::string sEOS = string16_EOSType(VolPhase->
m_eqnState);
1433 plogf(
"%16s %5d %5d %8d %16s %8d %16e ", VolPhase->
PhaseName.c_str(),
1441 print_char(
'=', 80);
1443 print_char(
'=', 20);
1444 plogf(
" Cantera_to_vprob: END OF PROBLEM STATEMENT ");
1445 print_char(
'=', 20);
1447 print_char(
'=', 80);
1458 nu.resize(nsp, 0.0);
1459 for (
size_t i = 0; i < nsp; i++) {
1466 if (rxn > nsp - nc) {
1469 size_t j = indSpecies[rxn + nc];
1471 for (
size_t kc = 0; kc < nc; kc++) {
1473 nu[j] = scMatrix[rxn][kc];
1546 plogf(
"problems\n");
1556 throw CanteraError(
"vcs_MultiPhaseEquil::determine_PhaseStability",
1557 "Temperature less than zero on input");
1561 throw CanteraError(
"vcs_MultiPhaseEquil::determine_PhaseStability",
1562 "Pressure less than zero on input");
1565 beginLogGroup(
"vcs_MultiPhaseEquil::determine_PhaseStability", loglevel);
1603 plogf(
"\n Results from vcs_PS:\n");
1610 plogf(
"Phase %d named %s is stable, function value = %g > 0\n", iph, sss.c_str(), funcStab);
1612 plogf(
"Phase %d named %s is not stable + function value = %g < 0\n", iph, sss.c_str(), funcStab);
1615 plogf(
"----------------------------------------"
1616 "---------------------\n");
1617 plogf(
" Name Mole_Number");
1623 plogf(
" Mole_Fraction Chem_Potential");
1625 plogf(
" (kcal/mol)\n");
1627 plogf(
" (Dimensionless)\n");
1629 plogf(
" (kJ/mol)\n");
1631 plogf(
" (Kelvin)\n");
1633 plogf(
" (J/kmol)\n");
1635 plogf(
"-------------------------------------------------------------\n");
1650 plogf(
"------------------------------------------"
1651 "-------------------\n");
1654 plogf(
"Total time = %12.6e seconds\n", te);