30 int printLvl,
double err,
31 int maxsteps,
int loglevel)
33 double Vtarget =
m_mix->volume();
34 if ((XY != TV) && (XY != HV) && (XY != UV) && (XY != SV)) {
35 throw CanteraError(
"vcs_MultiPhaseEquil::equilibrate_TV",
36 "Wrong XY flag: {}", XY);
41 m_mix->setTemperature(xtarget);
43 int strt = estimateEquil;
48 double Tlow = 0.5 *
m_mix->minTemp();
49 double Thigh = 2.0 *
m_mix->maxTemp();
50 int printLvlSub = std::max(0, printLvl - 1);
51 for (
int n = 0; n < maxiter; n++) {
52 double Pnow =
m_mix->pressure();
56 iSuccess =
equilibrate_TP(strt, printLvlSub, err, maxsteps, loglevel);
60 printLvlSub, err, maxsteps, loglevel);
64 printLvlSub, err, maxsteps, loglevel);
68 printLvlSub, err, maxsteps, loglevel);
74 double Vnow =
m_mix->volume();
88 double Verr = fabs((Vtarget - Vnow)/Vtarget);
95 double dVdP = (V2 - V1) / (P2 - P1);
100 Pnew = Pnow + (Vtarget - Vnow) / dVdP;
101 if (Pnew < 0.2 * Pnow) {
104 if (Pnew > 3.0 * Pnow) {
109 m_mix->setPressure(Pnow*1.01);
110 double dVdP = (
m_mix->volume() - Vnow)/(0.01*Pnow);
111 Pnew = Pnow + 0.5*(Vtarget - Vnow)/dVdP;
112 if (Pnew < 0.5* Pnow) {
115 if (Pnew > 1.7 * Pnow) {
119 m_mix->setPressure(Pnew);
122 "No convergence for V");
126 double Thigh,
int estimateEquil,
int printLvl,
double err,
int maxsteps,
131 if (XY != HP && XY != UP) {
132 throw CanteraError(
"vcs_MultiPhaseEquil::equilibrate_HP",
135 int strt = estimateEquil;
139 Tlow = 0.5 *
m_mix->minTemp();
142 if (Thigh <= 0.0 || Thigh > 1.0E6) {
143 Thigh = 2.0 *
m_mix->maxTemp();
148 double Hhigh =
Undef;
149 double Tnow =
m_mix->temperature();
150 int printLvlSub = std::max(printLvl - 1, 0);
152 for (
int n = 0; n < maxiter; n++) {
156 Tnow =
m_mix->temperature();
157 iSuccess =
equilibrate_TP(strt, printLvlSub, err, maxsteps, loglevel);
159 double Hnow = (XY == UP) ?
m_mix->IntEnergy() :
m_mix->enthalpy();
161 pmoles[0] =
m_mix->phaseMoles(0);
162 double Tmoles = pmoles[0];
163 double HperMole = Hnow/Tmoles;
165 plogf(
"T = %g, Hnow = %g ,Tmoles = %g, HperMole = %g\n",
166 Tnow, Hnow, Tmoles, HperMole);
172 if (Hnow < Htarget) {
187 cpb = (Hhigh - Hlow)/(Thigh - Tlow);
188 dT = (Htarget - Hnow)/cpb;
189 double dTa = fabs(dT);
190 double dTmax = 0.5*fabs(Thigh - Tlow);
195 double Tnew = sqrt(Tlow*Thigh);
196 dT =
clip(Tnew - Tnow, -200.0, 200.0);
198 double acpb = std::max(fabs(cpb), 1.0E-6);
199 double denom = std::max(fabs(Htarget), acpb);
200 double Herr = Htarget - Hnow;
201 double HConvErr = fabs((Herr)/denom);
203 plogf(
" equilibrate_HP: It = %d, Tcurr = %g Hcurr = %g, Htarget = %g\n",
204 n, Tnow, Hnow, Htarget);
205 plogf(
" H rel error = %g, cp = %g, HConvErr = %g\n",
206 Herr, cpb, HConvErr);
209 if (HConvErr < err) {
211 plogf(
" equilibrate_HP: CONVERGENCE: Hfinal = %g Tfinal = %g, Its = %d \n",
213 plogf(
" H rel error = %g, cp = %g, HConvErr = %g\n",
214 Herr, cpb, HConvErr);
218 double Tnew = Tnow + dT;
222 m_mix->setTemperature(Tnew);
224 if (!estimateEquil) {
227 double Tnew = 0.5*(Tnow + Thigh);
228 if (fabs(Tnew - Tnow) < 1.0) {
231 m_mix->setTemperature(Tnew);
235 throw CanteraError(
"vcs_MultiPhaseEquil::equilibrate_HP",
236 "No convergence for T");
240 int estimateEquil,
int printLvl,
double err,
int maxsteps,
int loglevel)
243 int strt = estimateEquil;
247 Tlow = 0.5 *
m_mix->minTemp();
250 if (Thigh <= 0.0 || Thigh > 1.0E6) {
251 Thigh = 2.0 *
m_mix->maxTemp();
254 double cpb = 1.0, dT;
256 double Shigh =
Undef;
257 double Tnow =
m_mix->temperature();
258 Tlow = std::min(Tnow, Tlow);
259 Thigh = std::max(Tnow, Thigh);
260 int printLvlSub = std::max(printLvl - 1, 0);
262 for (
int n = 0; n < maxiter; n++) {
266 Tnow =
m_mix->temperature();
267 int iSuccess =
equilibrate_TP(strt, printLvlSub, err, maxsteps, loglevel);
269 double Snow =
m_mix->entropy();
271 pmoles[0] =
m_mix->phaseMoles(0);
272 double Tmoles = pmoles[0];
273 double SperMole = Snow/Tmoles;
275 plogf(
"T = %g, Snow = %g ,Tmoles = %g, SperMole = %g\n",
276 Tnow, Snow, Tmoles, SperMole);
283 if (Snow < Starget) {
288 if (Slow > Starget && Snow < Slow) {
304 cpb = (Shigh - Slow)/(Thigh - Tlow);
305 dT = (Starget - Snow)/cpb;
306 double Tnew = Tnow + dT;
307 double dTa = fabs(dT);
308 double dTmax = 0.5*fabs(Thigh - Tlow);
309 if (Tnew > Thigh || Tnew < Tlow) {
310 dTmax = 1.5*fabs(Thigh - Tlow);
312 dTmax = std::min(dTmax, 300.);
317 double Tnew = sqrt(Tlow*Thigh);
321 double acpb = std::max(fabs(cpb), 1.0E-6);
322 double denom = std::max(fabs(Starget), acpb);
323 double Serr = Starget - Snow;
324 double SConvErr = fabs((Serr)/denom);
326 plogf(
" equilibrate_SP: It = %d, Tcurr = %g Scurr = %g, Starget = %g\n",
327 n, Tnow, Snow, Starget);
328 plogf(
" S rel error = %g, cp = %g, SConvErr = %g\n",
329 Serr, cpb, SConvErr);
332 if (SConvErr < err) {
334 plogf(
" equilibrate_SP: CONVERGENCE: Sfinal = %g Tfinal = %g, Its = %d \n",
336 plogf(
" S rel error = %g, cp = %g, HConvErr = %g\n",
337 Serr, cpb, SConvErr);
341 double Tnew = Tnow + dT;
345 m_mix->setTemperature(Tnew);
347 if (!estimateEquil) {
350 double Tnew = 0.5*(Tnow + Thigh);
351 if (fabs(Tnew - Tnow) < 1.0) {
354 m_mix->setTemperature(Tnew);
358 throw CanteraError(
"vcs_MultiPhaseEquil::equilibrate_SP",
359 "No convergence for T");
363 double err,
int maxsteps,
int loglevel)
367 return equilibrate_TP(estimateEquil, printLvl, err, maxsteps, loglevel);
368 }
else if (XY == HP || XY == UP) {
370 xtarget =
m_mix->enthalpy();
372 xtarget =
m_mix->IntEnergy();
374 double Tlow = 0.5 *
m_mix->minTemp();
375 double Thigh = 2.0 *
m_mix->maxTemp();
377 estimateEquil, printLvl, err, maxsteps, loglevel);
378 }
else if (XY == SP) {
379 xtarget =
m_mix->entropy();
380 double Tlow = 0.5 *
m_mix->minTemp();
381 double Thigh = 2.0 *
m_mix->maxTemp();
383 estimateEquil, printLvl, err, maxsteps, loglevel);
384 }
else if (XY == TV) {
385 xtarget =
m_mix->temperature();
387 estimateEquil, printLvl, err, maxsteps, loglevel);
388 }
else if (XY == HV) {
389 xtarget =
m_mix->enthalpy();
391 estimateEquil, printLvl, err, maxsteps, loglevel);
392 }
else if (XY == UV) {
393 xtarget =
m_mix->IntEnergy();
395 estimateEquil, printLvl, err, maxsteps, loglevel);
396 }
else if (XY == SV) {
397 xtarget =
m_mix->entropy();
399 printLvl, err, maxsteps, loglevel);
402 "Unsupported Option");
407 int maxsteps,
int loglevel)
409 int maxit = maxsteps;
413 m_vsolve.m_doEstimateEquil = estimateEquil;
417 if (
m_mix->temperature() <= 0.0) {
418 throw CanteraError(
"vcs_MultiPhaseEquil::equilibrate_TP",
419 "Temperature less than zero on input");
421 if (
m_mix->pressure() <= 0.0) {
422 throw CanteraError(
"vcs_MultiPhaseEquil::equilibrate_TP",
423 "Pressure less than zero on input");
434 int iSuccess =
m_vsolve.vcs(ipr, ip1, maxit);
438 vector<double> mu(
m_mix->nSpecies());
439 m_mix->getChemPotentials(mu.data());
440 plogf(
"\n Results from vcs:\n");
442 plogf(
"\nVCS FAILED TO CONVERGE!\n");
448 plogf(
"----------------------------------------"
449 "---------------------\n");
450 plogf(
" Name Mole_Number(kmol)");
451 plogf(
" Mole_Fraction Chem_Potential (J/kmol)\n");
452 plogf(
"--------------------------------------------------"
454 for (
size_t i = 0; i <
m_mix->nSpecies(); i++) {
457 plogf(
" %15.3e %15.3e ", 0.0,
m_mix->moleFraction(i));
458 plogf(
"%15.3e\n", mu[i]);
460 plogf(
" %15.3e %15.3e ",
m_mix->speciesMoles(i),
m_mix->moleFraction(i));
461 if (
m_mix->speciesMoles(i) <= 0.0) {
465 plogf(
" -1.000e+300\n");
467 plogf(
"%15.3e\n", mu[i]);
470 plogf(
"%15.3e\n", mu[i]);
474 plogf(
"------------------------------------------"
475 "-------------------\n");
476 if (printLvl > 2 &&
m_vsolve.m_timing_print_lvl > 0) {
477 plogf(
"Total time = %12.6e seconds\n", te);
485 size_t nphase =
m_vsolve.m_numPhases;
487 FILE* FP = fopen(reportFile.c_str(),
"w");
490 "Failure to open file");
492 vector<double> VolPM;
493 vector<double> activity;
497 vector<double> molalities;
500 for (
size_t iphase = 0; iphase < nphase; iphase++) {
503 VolPM.resize(nSpecies, 0.0);
508 double VolPhaseVolumes = 0.0;
509 for (
size_t k = 0; k < nSpecies; k++) {
512 VolPhaseVolumes *= TMolesPhase;
513 vol += VolPhaseVolumes;
516 fprintf(FP,
"--------------------- VCS_MULTIPHASE_EQUIL FINAL REPORT"
517 " -----------------------------\n");
518 fprintf(FP,
"Temperature = %11.5g kelvin\n",
m_mix->temperature());
519 fprintf(FP,
"Pressure = %11.5g Pascal\n",
m_mix->pressure());
520 fprintf(FP,
"Total Volume = %11.5g m**3\n", vol);
521 fprintf(FP,
"Number Basis optimizations = %d\n",
m_vsolve.m_VCount->Basis_Opts);
522 fprintf(FP,
"Number VCS iterations = %d\n",
m_vsolve.m_VCount->Its);
524 for (
size_t iphase = 0; iphase < nphase; iphase++) {
526 string phaseName = tref.
name();
530 activity.resize(nSpecies, 0.0);
531 ac.resize(nSpecies, 0.0);
532 mu0.resize(nSpecies, 0.0);
533 mu.resize(nSpecies, 0.0);
534 VolPM.resize(nSpecies, 0.0);
535 molalities.resize(nSpecies, 0.0);
542 double VolPhaseVolumes = 0.0;
543 for (
size_t k = 0; k < nSpecies; k++) {
546 VolPhaseVolumes *= TMolesPhase;
547 vol += VolPhaseVolumes;
549 if (actConvention == 1) {
555 fprintf(FP,
" Name, Phase, PhaseMoles, Mole_Fract, "
556 "Molalities, ActCoeff, Activity,"
557 "ChemPot_SS0, ChemPot, mole_num, PMVol, Phase_Volume\n");
559 fprintf(FP,
" , , (kmol), , "
561 " (J/kmol), (J/kmol), (kmol), (m**3/kmol), (m**3)\n");
563 for (
size_t k = 0; k < nSpecies; k++) {
565 fprintf(FP,
"%12s, %11s, %11.3e, %11.3e, %11.3e, %11.3e, %11.3e,"
566 "%11.3e, %11.3e, %11.3e, %11.3e, %11.3e\n",
568 phaseName.c_str(), TMolesPhase,
569 tref.
moleFraction(k), molalities[k], ac[k], activity[k],
570 mu0[k]*1.0E-6, mu[k]*1.0E-6,
572 VolPM[k], VolPhaseVolumes);
576 fprintf(FP,
" Name, Phase, PhaseMoles, Mole_Fract, "
577 "Molalities, ActCoeff, Activity,"
578 " ChemPotSS0, ChemPot, mole_num, PMVol, Phase_Volume\n");
580 fprintf(FP,
" , , (kmol), , "
582 " (J/kmol), (J/kmol), (kmol), (m**3/kmol), (m**3)\n");
584 for (
size_t k = 0; k < nSpecies; k++) {
587 for (
size_t k = 0; k < nSpecies; k++) {
589 fprintf(FP,
"%12s, %11s, %11.3e, %11.3e, %11.3e, %11.3e, %11.3e, "
590 "%11.3e, %11.3e,% 11.3e, %11.3e, %11.3e\n",
592 phaseName.c_str(), TMolesPhase,
594 activity[k], mu0[k]*1.0E-6, mu[k]*1.0E-6,
596 VolPM[k], VolPhaseVolumes);
ThermoPhase object for the ideal molal equation of state (see Thermodynamic Properties and class Idea...
Header file for an ideal solid solution model with incompressible thermodynamics (see Thermodynamic P...
Base class for exceptions thrown by Cantera classes.
MolalityVPSSTP is a derived class of ThermoPhase that handles variable pressure standard state method...
void getMolalities(double *const molal) const
This function will return the molalities of the species.
A class for multiphase mixtures.
size_t nSpecies() const
Returns the number of species in the phase.
string speciesName(size_t k) const
Name of the species with index k.
double moleFraction(size_t k) const
Return the mole fraction of a single species.
string name() const
Return the name of the phase.
Base class for a phase with thermodynamic properties.
virtual void getActivityCoefficients(double *ac) const
Get the array of non-dimensional molar-based activity coefficients at the current solution temperatur...
virtual int activityConvention() const
This method returns the convention used in specification of the activities, of which there are curren...
virtual void getActivities(double *a) const
Get the array of non-dimensional activities at the current solution temperature, pressure,...
virtual void getStandardChemPotentials(double *mu) const
Get the array of chemical potentials at unit activity for the species at their standard states at the...
virtual void getChemPotentials(double *mu) const
Get the species chemical potentials. Units: J/kmol.
virtual void getPartialMolarVolumes(double *vbar) const
Return an array of partial molar volumes for the species in the mixture.
The class provides the wall clock timer in seconds.
double secondsWC()
Returns the wall clock time in seconds since the last reset.
VCS_SOLVE m_vsolve
The object that contains the problem statement and does all of the equilibration work.
int equilibrate_SP(double Starget, double Tlow, double Thigh, int estimateEquil=0, int printLvl=0, double err=1.0E-6, int maxsteps=VCS_MAXSTEPS, int loglevel=-99)
Equilibrate the solution using the current element abundances stored in the MultiPhase object using c...
void reportCSV(const string &reportFile)
Report the equilibrium answer in a comma separated table format.
vcs_MultiPhaseEquil(MultiPhase *mix, int printLvl)
Constructor for the multiphase equilibrium solver.
int equilibrate_TP(int estimateEquil=0, int printLvl=0, double err=1.0e-6, int maxsteps=VCS_MAXSTEPS, int loglevel=-99)
Equilibrate the solution using the current element abundances stored in the MultiPhase object using c...
int equilibrate(int XY, int estimateEquil=0, int printLvl=0, double err=1.0e-6, int maxsteps=VCS_MAXSTEPS, int loglevel=-99)
Equilibrate the solution using the current element abundances stored in the MultiPhase object.
int equilibrate_TV(int XY, double xtarget, int estimateEquil=0, int printLvl=0, double err=1.0E-6, int maxsteps=VCS_MAXSTEPS, int logLevel=-99)
Equilibrate the solution using the current element abundances stored in the MultiPhase object using c...
int m_printLvl
Print level from the VCSnonlinear package.
int equilibrate_HP(double Htarget, int XY, double Tlow, double Thigh, int estimateEquil=0, int printLvl=0, double err=1.0E-6, int maxsteps=VCS_MAXSTEPS, int loglevel=-99)
Equilibrate the solution using the current element abundances stored in the MultiPhase object using e...
MultiPhase * m_mix
Pointer to the MultiPhase mixture that will be equilibrated.
Phase information and Phase calculations for vcs.
size_t nSpecies() const
Return the number of species in the phase.
double totalMoles() const
Return the total moles in the phase.
Declarations for a simple class that implements an Ansi C wall clock timer (see clockWC).
T clip(const T &value, const T &lower, const T &upper)
Clip value such that lower <= value <= upper.
Namespace for the Cantera kernel.
const double Undef
Fairly random number to be used to initialize variables against to see if they are subsequently defin...
Contains const definitions for types of species reference-state thermodynamics managers (see Species ...
Contains declarations for string manipulation functions within Cantera.
Interface class for the vcsnonlinear solver.
Header for the object representing each phase within vcs.
#define VCS_SPECIES_TYPE_INTERFACIALVOLTAGE
Unknown refers to the voltage level of a phase.
#define plogf
define this Cantera function to replace printf