Cantera  3.3.0a1
Loading...
Searching...
No Matches
vcs_MultiPhaseEquil.cpp
Go to the documentation of this file.
1/**
2 * @file vcs_MultiPhaseEquil.cpp
3 * Driver routine for the VCSnonideal equilibrium solver package
4 */
5
6// This file is part of Cantera. See License.txt in the top-level directory or
7// at https://cantera.org/license.txt for license and copyright information.
8
15
16namespace Cantera
17{
19 m_mix(mix),
20 m_printLvl(printLvl),
21 m_vsolve(mix, printLvl)
22{
23}
24
25int vcs_MultiPhaseEquil::equilibrate_TV(int XY, double xtarget, int estimateEquil,
26 int printLvl, double err,
27 int maxsteps, int loglevel)
28{
29 double Vtarget = m_mix->volume();
30 if ((XY != TV) && (XY != HV) && (XY != UV) && (XY != SV)) {
31 throw CanteraError("vcs_MultiPhaseEquil::equilibrate_TV",
32 "Wrong XY flag: {}", XY);
33 }
34 int maxiter = 100;
35 int iSuccess = 0;
36 if (XY == TV) {
37 m_mix->setTemperature(xtarget);
38 }
39 int strt = estimateEquil;
40 double P1 = 0.0;
41 double V1 = 0.0;
42 double V2 = 0.0;
43 double P2 = 0.0;
44 double Tlow = 0.5 * m_mix->minTemp();
45 double Thigh = 2.0 * m_mix->maxTemp();
46 int printLvlSub = std::max(0, printLvl - 1);
47 for (int n = 0; n < maxiter; n++) {
48 double Pnow = m_mix->pressure();
49
50 switch (XY) {
51 case TV:
52 iSuccess = equilibrate_TP(strt, printLvlSub, err, maxsteps, loglevel);
53 break;
54 case HV:
55 iSuccess = equilibrate_HP(xtarget, HP, Tlow, Thigh, strt,
56 printLvlSub, err, maxsteps, loglevel);
57 break;
58 case UV:
59 iSuccess = equilibrate_HP(xtarget, UP, Tlow, Thigh, strt,
60 printLvlSub, err, maxsteps, loglevel);
61 break;
62 case SV:
63 iSuccess = equilibrate_SP(xtarget, Tlow, Thigh, strt,
64 printLvlSub, err, maxsteps, loglevel);
65 break;
66 default:
67 break;
68 }
69 strt = false;
70 double Vnow = m_mix->volume();
71 if (n == 0) {
72 V2 = Vnow;
73 P2 = Pnow;
74 } else if (n == 1) {
75 V1 = Vnow;
76 P1 = Pnow;
77 } else {
78 P2 = P1;
79 V2 = V1;
80 P1 = Pnow;
81 V1 = Vnow;
82 }
83
84 double Verr = fabs((Vtarget - Vnow)/Vtarget);
85 if (Verr < err) {
86 return iSuccess;
87 }
88 double Pnew;
89 // find dV/dP
90 if (n > 1) {
91 double dVdP = (V2 - V1) / (P2 - P1);
92 if (dVdP == 0.0) {
93 throw CanteraError("vcs_MultiPhase::equilibrate_TV",
94 "dVdP == 0.0");
95 } else {
96 Pnew = Pnow + (Vtarget - Vnow) / dVdP;
97 if (Pnew < 0.2 * Pnow) {
98 Pnew = 0.2 * Pnow;
99 }
100 if (Pnew > 3.0 * Pnow) {
101 Pnew = 3.0 * Pnow;
102 }
103 }
104 } else {
105 m_mix->setPressure(Pnow*1.01);
106 double dVdP = (m_mix->volume() - Vnow)/(0.01*Pnow);
107 Pnew = Pnow + 0.5*(Vtarget - Vnow)/dVdP;
108 if (Pnew < 0.5* Pnow) {
109 Pnew = 0.5 * Pnow;
110 }
111 if (Pnew > 1.7 * Pnow) {
112 Pnew = 1.7 * Pnow;
113 }
114 }
115 m_mix->setPressure(Pnew);
116 }
117 throw CanteraError("vcs_MultiPhase::equilibrate_TV",
118 "No convergence for V");
119}
120
121int vcs_MultiPhaseEquil::equilibrate_HP(double Htarget, int XY, double Tlow,
122 double Thigh, int estimateEquil, int printLvl, double err, int maxsteps,
123 int loglevel)
124{
125 int maxiter = 100;
126 int iSuccess;
127 if (XY != HP && XY != UP) {
128 throw CanteraError("vcs_MultiPhaseEquil::equilibrate_HP",
129 "Wrong XP", XY);
130 }
131 int strt = estimateEquil;
132
133 // Lower bound on T. This will change as we progress in the calculation
134 if (Tlow <= 0.0) {
135 Tlow = 0.5 * m_mix->minTemp();
136 }
137 // Upper bound on T. This will change as we progress in the calculation
138 if (Thigh <= 0.0 || Thigh > 1.0E6) {
139 Thigh = 2.0 * m_mix->maxTemp();
140 }
141
142 double cpb = 1.0;
143 double Hlow = Undef;
144 double Hhigh = Undef;
145 double Tnow = m_mix->temperature();
146 int printLvlSub = std::max(printLvl - 1, 0);
147
148 for (int n = 0; n < maxiter; n++) {
149 // start with a loose error tolerance, but tighten it as we get
150 // close to the final temperature
151 try {
152 Tnow = m_mix->temperature();
153 iSuccess = equilibrate_TP(strt, printLvlSub, err, maxsteps, loglevel);
154 strt = 0;
155 double Hnow = (XY == UP) ? m_mix->IntEnergy() : m_mix->enthalpy();
156 double pmoles[10];
157 pmoles[0] = m_mix->phaseMoles(0);
158 double Tmoles = pmoles[0];
159 double HperMole = Hnow/Tmoles;
160 if (printLvl > 0) {
161 plogf("T = %g, Hnow = %g ,Tmoles = %g, HperMole = %g\n",
162 Tnow, Hnow, Tmoles, HperMole);
163 }
164
165 // the equilibrium enthalpy monotonically increases with T;
166 // if the current value is below the target, then we know the
167 // current temperature is too low. Set the lower bounds.
168 if (Hnow < Htarget) {
169 if (Tnow > Tlow) {
170 Tlow = Tnow;
171 Hlow = Hnow;
172 }
173 } else {
174 // the current enthalpy is greater than the target; therefore
175 // the current temperature is too high. Set the high bounds.
176 if (Tnow < Thigh) {
177 Thigh = Tnow;
178 Hhigh = Hnow;
179 }
180 }
181 double dT;
182 if (Hlow != Undef && Hhigh != Undef) {
183 cpb = (Hhigh - Hlow)/(Thigh - Tlow);
184 dT = (Htarget - Hnow)/cpb;
185 double dTa = fabs(dT);
186 double dTmax = 0.5*fabs(Thigh - Tlow);
187 if (dTa > dTmax) {
188 dT *= dTmax/dTa;
189 }
190 } else {
191 double Tnew = sqrt(Tlow*Thigh);
192 dT = clip(Tnew - Tnow, -200.0, 200.0);
193 }
194 double acpb = std::max(fabs(cpb), 1.0E-6);
195 double denom = std::max(fabs(Htarget), acpb);
196 double Herr = Htarget - Hnow;
197 double HConvErr = fabs((Herr)/denom);
198 if (printLvl > 0) {
199 plogf(" equilibrate_HP: It = %d, Tcurr = %g Hcurr = %g, Htarget = %g\n",
200 n, Tnow, Hnow, Htarget);
201 plogf(" H rel error = %g, cp = %g, HConvErr = %g\n",
202 Herr, cpb, HConvErr);
203 }
204
205 if (HConvErr < err) { // || dTa < 1.0e-4) {
206 if (printLvl > 0) {
207 plogf(" equilibrate_HP: CONVERGENCE: Hfinal = %g Tfinal = %g, Its = %d \n",
208 Hnow, Tnow, n);
209 plogf(" H rel error = %g, cp = %g, HConvErr = %g\n",
210 Herr, cpb, HConvErr);
211 }
212 return iSuccess;
213 }
214 double Tnew = Tnow + dT;
215 if (Tnew < 0.0) {
216 Tnew = 0.5*Tnow;
217 }
218 m_mix->setTemperature(Tnew);
219 } catch (const CanteraError&) {
220 if (!estimateEquil) {
221 strt = -1;
222 } else {
223 double Tnew = 0.5*(Tnow + Thigh);
224 if (fabs(Tnew - Tnow) < 1.0) {
225 Tnew = Tnow + 1.0;
226 }
227 m_mix->setTemperature(Tnew);
228 }
229 }
230 }
231 throw CanteraError("vcs_MultiPhaseEquil::equilibrate_HP",
232 "No convergence for T");
233}
234
235int vcs_MultiPhaseEquil::equilibrate_SP(double Starget, double Tlow, double Thigh,
236 int estimateEquil, int printLvl, double err, int maxsteps, int loglevel)
237{
238 int maxiter = 100;
239 int strt = estimateEquil;
240
241 // Lower bound on T. This will change as we progress in the calculation
242 if (Tlow <= 0.0) {
243 Tlow = 0.5 * m_mix->minTemp();
244 }
245 // Upper bound on T. This will change as we progress in the calculation
246 if (Thigh <= 0.0 || Thigh > 1.0E6) {
247 Thigh = 2.0 * m_mix->maxTemp();
248 }
249
250 double cpb = 1.0, dT;
251 double Slow = Undef;
252 double Shigh = Undef;
253 double Tnow = m_mix->temperature();
254 Tlow = std::min(Tnow, Tlow);
255 Thigh = std::max(Tnow, Thigh);
256 int printLvlSub = std::max(printLvl - 1, 0);
257
258 for (int n = 0; n < maxiter; n++) {
259 // start with a loose error tolerance, but tighten it as we get
260 // close to the final temperature
261 try {
262 Tnow = m_mix->temperature();
263 int iSuccess = equilibrate_TP(strt, printLvlSub, err, maxsteps, loglevel);
264 strt = 0;
265 double Snow = m_mix->entropy();
266 double pmoles[10];
267 pmoles[0] = m_mix->phaseMoles(0);
268 double Tmoles = pmoles[0];
269 double SperMole = Snow/Tmoles;
270 if (printLvl > 0) {
271 plogf("T = %g, Snow = %g ,Tmoles = %g, SperMole = %g\n",
272 Tnow, Snow, Tmoles, SperMole);
273 }
274
275 // the equilibrium entropy monotonically increases with T;
276 // if the current value is below the target, then we know the
277 // current temperature is too low. Set the lower bounds to the
278 // current condition.
279 if (Snow < Starget) {
280 if (Tnow > Tlow) {
281 Tlow = Tnow;
282 Slow = Snow;
283 } else {
284 if (Slow > Starget && Snow < Slow) {
285 Thigh = Tlow;
286 Shigh = Slow;
287 Tlow = Tnow;
288 Slow = Snow;
289 }
290 }
291 } else {
292 // the current enthalpy is greater than the target; therefore
293 // the current temperature is too high. Set the high bounds.
294 if (Tnow < Thigh) {
295 Thigh = Tnow;
296 Shigh = Snow;
297 }
298 }
299 if (Slow != Undef && Shigh != Undef) {
300 cpb = (Shigh - Slow)/(Thigh - Tlow);
301 dT = (Starget - Snow)/cpb;
302 double Tnew = Tnow + dT;
303 double dTa = fabs(dT);
304 double dTmax = 0.5*fabs(Thigh - Tlow);
305 if (Tnew > Thigh || Tnew < Tlow) {
306 dTmax = 1.5*fabs(Thigh - Tlow);
307 }
308 dTmax = std::min(dTmax, 300.);
309 if (dTa > dTmax) {
310 dT *= dTmax/dTa;
311 }
312 } else {
313 double Tnew = sqrt(Tlow*Thigh);
314 dT = Tnew - Tnow;
315 }
316
317 double acpb = std::max(fabs(cpb), 1.0E-6);
318 double denom = std::max(fabs(Starget), acpb);
319 double Serr = Starget - Snow;
320 double SConvErr = fabs((Serr)/denom);
321 if (printLvl > 0) {
322 plogf(" equilibrate_SP: It = %d, Tcurr = %g Scurr = %g, Starget = %g\n",
323 n, Tnow, Snow, Starget);
324 plogf(" S rel error = %g, cp = %g, SConvErr = %g\n",
325 Serr, cpb, SConvErr);
326 }
327
328 if (SConvErr < err) { // || dTa < 1.0e-4) {
329 if (printLvl > 0) {
330 plogf(" equilibrate_SP: CONVERGENCE: Sfinal = %g Tfinal = %g, Its = %d \n",
331 Snow, Tnow, n);
332 plogf(" S rel error = %g, cp = %g, HConvErr = %g\n",
333 Serr, cpb, SConvErr);
334 }
335 return iSuccess;
336 }
337 double Tnew = Tnow + dT;
338 if (Tnew < 0.0) {
339 Tnew = 0.5*Tnow;
340 }
341 m_mix->setTemperature(Tnew);
342 } catch (const CanteraError&) {
343 if (!estimateEquil) {
344 strt = -1;
345 } else {
346 double Tnew = 0.5*(Tnow + Thigh);
347 if (fabs(Tnew - Tnow) < 1.0) {
348 Tnew = Tnow + 1.0;
349 }
350 m_mix->setTemperature(Tnew);
351 }
352 }
353 }
354 throw CanteraError("vcs_MultiPhaseEquil::equilibrate_SP",
355 "No convergence for T");
356}
357
358int vcs_MultiPhaseEquil::equilibrate(int XY, int estimateEquil, int printLvl,
359 double err, int maxsteps, int loglevel)
360{
361 double xtarget;
362 if (XY == TP) {
363 return equilibrate_TP(estimateEquil, printLvl, err, maxsteps, loglevel);
364 } else if (XY == HP || XY == UP) {
365 if (XY == HP) {
366 xtarget = m_mix->enthalpy();
367 } else {
368 xtarget = m_mix->IntEnergy();
369 }
370 double Tlow = 0.5 * m_mix->minTemp();
371 double Thigh = 2.0 * m_mix->maxTemp();
372 return equilibrate_HP(xtarget, XY, Tlow, Thigh,
373 estimateEquil, printLvl, err, maxsteps, loglevel);
374 } else if (XY == SP) {
375 xtarget = m_mix->entropy();
376 double Tlow = 0.5 * m_mix->minTemp();
377 double Thigh = 2.0 * m_mix->maxTemp();
378 return equilibrate_SP(xtarget, Tlow, Thigh,
379 estimateEquil, printLvl, err, maxsteps, loglevel);
380 } else if (XY == TV) {
381 xtarget = m_mix->temperature();
382 return equilibrate_TV(XY, xtarget,
383 estimateEquil, printLvl, err, maxsteps, loglevel);
384 } else if (XY == HV) {
385 xtarget = m_mix->enthalpy();
386 return equilibrate_TV(XY, xtarget,
387 estimateEquil, printLvl, err, maxsteps, loglevel);
388 } else if (XY == UV) {
389 xtarget = m_mix->IntEnergy();
390 return equilibrate_TV(XY, xtarget,
391 estimateEquil, printLvl, err, maxsteps, loglevel);
392 } else if (XY == SV) {
393 xtarget = m_mix->entropy();
394 return equilibrate_TV(XY, xtarget, estimateEquil,
395 printLvl, err, maxsteps, loglevel);
396 } else {
397 throw CanteraError("vcs_MultiPhaseEquil::equilibrate",
398 "Unsupported Option");
399 }
400}
401
402int vcs_MultiPhaseEquil::equilibrate_TP(int estimateEquil, int printLvl, double err,
403 int maxsteps, int loglevel)
404{
405 int maxit = maxsteps;
406 m_printLvl = printLvl;
407 m_vsolve.m_printLvl = printLvl;
408 m_vsolve.m_doEstimateEquil = estimateEquil;
409
410 // Check obvious bounds on the temperature and pressure NOTE, we may want to
411 // do more here with the real bounds given by the ThermoPhase objects.
412 if (m_mix->temperature() <= 0.0) {
413 throw CanteraError("vcs_MultiPhaseEquil::equilibrate_TP",
414 "Temperature less than zero on input");
415 }
416 if (m_mix->pressure() <= 0.0) {
417 throw CanteraError("vcs_MultiPhaseEquil::equilibrate_TP",
418 "Pressure less than zero on input");
419 }
420
421 //! Call the thermo Program
422 int ip1 = m_printLvl;
423 int ipr = std::max(0, m_printLvl-1);
424 if (m_printLvl >= 3) {
425 ip1 = m_printLvl - 2;
426 } else {
427 ip1 = 0;
428 }
429 int iSuccess = m_vsolve.solve_TP(ipr, ip1, maxit);
430
431 if (printLvl > 0) {
432 vector<double> mu(m_mix->nSpecies());
433 m_mix->getChemPotentials(mu.data());
434 plogf("\n Results from vcs:\n");
435 if (iSuccess != 0) {
436 plogf("\nVCS FAILED TO CONVERGE!\n");
437 }
438 plogf("\n");
439 plogf("Temperature = %g Kelvin\n", m_vsolve.m_temperature);
440 plogf("Pressure = %g Pa\n", m_vsolve.m_pressurePA);
441 plogf("\n");
442 plogf("----------------------------------------"
443 "---------------------\n");
444 plogf(" Name Mole_Number(kmol)");
445 plogf(" Mole_Fraction Chem_Potential (J/kmol)\n");
446 plogf("--------------------------------------------------"
447 "-----------\n");
448 for (size_t i = 0; i < m_mix->nSpecies(); i++) {
449 plogf("%-12s", m_mix->speciesName(i));
451 plogf(" %15.3e %15.3e ", 0.0, m_mix->moleFraction(i));
452 plogf("%15.3e\n", mu[i]);
453 } else {
454 plogf(" %15.3e %15.3e ", m_mix->speciesMoles(i), m_mix->moleFraction(i));
455 if (m_mix->speciesMoles(i) <= 0.0) {
456 size_t iph = m_vsolve.m_phaseID[i];
457 vcs_VolPhase* VPhase = m_vsolve.m_VolPhaseList[iph].get();
458 if (VPhase->nSpecies() > 1) {
459 plogf(" -1.000e+300\n");
460 } else {
461 plogf("%15.3e\n", mu[i]);
462 }
463 } else {
464 plogf("%15.3e\n", mu[i]);
465 }
466 }
467 }
468 plogf("------------------------------------------"
469 "-------------------\n");
470 }
471 return iSuccess;
472}
473
474}
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.
A class for multiphase mixtures.
Definition MultiPhase.h:62
double speciesMoles(size_t kGlob) const
Returns the moles of global species k. units = kmol.
size_t nSpecies() const
Number of species, summed over all phases.
Definition MultiPhase.h:143
double enthalpy() const
The enthalpy of the mixture [J].
double pressure() const
Pressure [Pa].
Definition MultiPhase.h:409
double minTemp() const
Minimum temperature for which all solution phases have valid thermo data.
Definition MultiPhase.h:267
double entropy() const
The entropy of the mixture [J/K].
double temperature() const
Temperature [K].
Definition MultiPhase.h:349
void getChemPotentials(double *mu) const
Returns a vector of Chemical potentials.
double moleFraction(const size_t kGlob) const
Returns the mole fraction of global species k.
string speciesName(size_t kGlob) const
Name of species with global index kGlob.
void setPressure(double P)
Set the pressure [Pa].
Definition MultiPhase.h:424
double phaseMoles(const size_t n) const
Return the number of moles in phase n.
double volume() const
The total mixture volume [m^3].
void setTemperature(const double T)
Set the temperature [K].
double maxTemp() const
Maximum temperature for which all solution phases have valid thermo data.
Definition MultiPhase.h:274
double IntEnergy() const
The internal energy of the mixture [J].
int m_doEstimateEquil
Setting for whether to do an initial estimate.
Definition vcs_solve.h:953
vector< size_t > m_phaseID
Mapping from the species number to the phase number.
Definition vcs_solve.h:1157
vector< int > m_speciesUnknownType
Specifies the species unknown type.
Definition vcs_solve.h:973
int solve_TP(int print_lvl, int printDetails, int maxit)
Main routine that solves for equilibrium at constant T and P using a variant of the VCS method.
vector< unique_ptr< vcs_VolPhase > > m_VolPhaseList
Array of Phase Structures. Length = number of phases.
Definition vcs_solve.h:1191
double m_pressurePA
Pressure.
Definition vcs_solve.h:1080
int m_printLvl
Print level for print routines.
Definition vcs_solve.h:806
double m_temperature
Temperature (Kelvin)
Definition vcs_solve.h:1077
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...
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.
T clip(const T &value, const T &lower, const T &upper)
Clip value such that lower <= value <= upper.
Definition global.h:326
Namespace for the Cantera kernel.
Definition AnyMap.cpp:595
const double Undef
Fairly random number to be used to initialize variables against to see if they are subsequently defin...
Definition ct_defs.h:164
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.
Definition vcs_defs.h:197
#define plogf
define this Cantera function to replace printf