Cantera 2.6.0
ThermoPhase.cpp
Go to the documentation of this file.
1/**
2 * @file ThermoPhase.cpp
3 * Definition file for class ThermoPhase, the base class for phases with
4 * thermodynamic properties
5 * (see class \link Cantera::ThermoPhase ThermoPhase\endlink).
6 */
7
8// This file is part of Cantera. See License.txt in the top-level directory or
9// at https://cantera.org/license.txt for license and copyright information.
10
18#include "cantera/base/ctml.h"
19
20#include <iomanip>
21#include <fstream>
22#include <numeric>
23
24using namespace std;
25
26namespace Cantera
27{
28
30 m_speciesData(0),
31 m_phi(0.0),
32 m_chargeNeutralityNecessary(false),
33 m_ssConvention(cSS_CONVENTION_TEMPERATURE),
34 m_tlast(0.0)
35{
36}
37
38ThermoPhase::~ThermoPhase()
39{
40 for (size_t k = 0; k < m_speciesData.size(); k++) {
41 delete m_speciesData[k];
42 }
43}
44
46 if (k != npos) {
48 } else {
49 for (size_t k = 0; k < nSpecies(); k++) {
51 }
52 }
54}
55
57{
59}
60
62{
63 return m_ssConvention;
64}
65
67{
68 // kmol/m^3 for bulk phases, kmol/m^2 for surface phases, etc.
69 return Units(1.0, 0, -static_cast<double>(nDim()), 0, 0, 0, 1);
70}
71
72doublereal ThermoPhase::logStandardConc(size_t k) const
73{
74 return log(standardConcentration(k));
75}
76
77void ThermoPhase::getActivities(doublereal* a) const
78{
80 for (size_t k = 0; k < nSpecies(); k++) {
81 a[k] /= standardConcentration(k);
82 }
83}
84
85void ThermoPhase::getLnActivityCoefficients(doublereal* lnac) const
86{
88 for (size_t k = 0; k < m_kk; k++) {
89 lnac[k] = std::log(lnac[k]);
90 }
91}
92
93void ThermoPhase::getElectrochemPotentials(doublereal* mu) const
94{
96 double ve = Faraday * electricPotential();
97 for (size_t k = 0; k < m_kk; k++) {
98 mu[k] += ve*charge(k);
99 }
100}
101
102void ThermoPhase::setState_TPX(doublereal t, doublereal p, const doublereal* x)
103{
105 setState_TP(t,p);
106}
107
108void ThermoPhase::setState_TPX(doublereal t, doublereal p, const compositionMap& x)
109{
111 setState_TP(t,p);
112}
113
114void ThermoPhase::setState_TPX(doublereal t, doublereal p, const std::string& x)
115{
117 setState_TP(t,p);
118}
119
120void ThermoPhase::setState_TPY(doublereal t, doublereal p, const doublereal* y)
121{
123 setState_TP(t,p);
124}
125
126void ThermoPhase::setState_TPY(doublereal t, doublereal p, const compositionMap& y)
127{
129 setState_TP(t,p);
130}
131
132void ThermoPhase::setState_TPY(doublereal t, doublereal p, const std::string& y)
133{
135 setState_TP(t,p);
136}
137
138void ThermoPhase::setState_TP(doublereal t, doublereal p)
139{
140 double tsave = temperature();
141 double dsave = density();
142 try {
144 setPressure(p);
145 } catch (CanteraError&) {
146 setState_TR(tsave, dsave);
147 throw;
148 }
149}
150
151void ThermoPhase::setState_RPX(doublereal rho, doublereal p, const doublereal* x)
152{
154 setState_RP(rho, p);
155}
156
157void ThermoPhase::setState_RPX(doublereal rho, doublereal p, const compositionMap& x)
158{
160 setState_RP(rho,p);
161}
162
163void ThermoPhase::setState_RPX(doublereal rho, doublereal p, const std::string& x)
164{
166 setState_RP(rho,p);
167}
168
169void ThermoPhase::setState_RPY(doublereal rho, doublereal p, const doublereal* y)
170{
172 setState_RP(rho,p);
173}
174
175void ThermoPhase::setState_RPY(doublereal rho, doublereal p, const compositionMap& y)
176{
178 setState_RP(rho,p);
179}
180
181void ThermoPhase::setState_RPY(doublereal rho, doublereal p, const std::string& y)
182{
184 setState_RP(rho,p);
185}
186
187void ThermoPhase::setState_PX(doublereal p, doublereal* x)
188{
190 setPressure(p);
191}
192
193void ThermoPhase::setState_PY(doublereal p, doublereal* y)
194{
196 setPressure(p);
197}
198
199void ThermoPhase::setState_HP(double Htarget, double p, double rtol)
200{
201 setState_HPorUV(Htarget, p, rtol, false);
202}
203
204void ThermoPhase::setState_UV(double u, double v, double rtol)
205{
206 assertCompressible("setState_UV");
207 setState_HPorUV(u, v, rtol, true);
208}
209
210void ThermoPhase::setState(const AnyMap& input_state)
211{
212 AnyMap state = input_state;
213
214 // Remap allowable synonyms
215 if (state.hasKey("mass-fractions")) {
216 state["Y"] = state["mass-fractions"];
217 state.erase("mass-fractions");
218 }
219 if (state.hasKey("mole-fractions")) {
220 state["X"] = state["mole-fractions"];
221 state.erase("mole-fractions");
222 }
223 if (state.hasKey("temperature")) {
224 state["T"] = state["temperature"];
225 }
226 if (state.hasKey("pressure")) {
227 state["P"] = state["pressure"];
228 }
229 if (state.hasKey("enthalpy")) {
230 state["H"] = state["enthalpy"];
231 }
232 if (state.hasKey("int-energy")) {
233 state["U"] = state["int-energy"];
234 }
235 if (state.hasKey("internal-energy")) {
236 state["U"] = state["internal-energy"];
237 }
238 if (state.hasKey("specific-volume")) {
239 state["V"] = state["specific-volume"];
240 }
241 if (state.hasKey("entropy")) {
242 state["S"] = state["entropy"];
243 }
244 if (state.hasKey("density")) {
245 state["D"] = state["density"];
246 }
247 if (state.hasKey("vapor-fraction")) {
248 state["Q"] = state["vapor-fraction"];
249 }
250
251 // Set composition
252 if (state.hasKey("X")) {
253 if (state["X"].is<string>()) {
254 setMoleFractionsByName(state["X"].asString());
255 } else {
256 setMoleFractionsByName(state["X"].asMap<double>());
257 }
258 state.erase("X");
259 } else if (state.hasKey("Y")) {
260 if (state["Y"].is<string>()) {
261 setMassFractionsByName(state["Y"].asString());
262 } else {
263 setMassFractionsByName(state["Y"].asMap<double>());
264 }
265 state.erase("Y");
266 }
267 // set thermodynamic state using whichever property set is found
268 if (state.size() == 0) {
269 setState_TP(298.15, OneAtm);
270 } else if (state.hasKey("T") && state.hasKey("P")) {
271 double T = state.convert("T", "K");
272 double P = state.convert("P", "Pa");
273 if (state.hasKey("Q")) {
274 setState_TPQ(T, P, state["Q"].asDouble());
275 } else {
276 setState_TP(T, P);
277 }
278 } else if (state.hasKey("T") && state.hasKey("D")) {
279 setState_TR(state.convert("T", "K"), state.convert("D", "kg/m^3"));
280 } else if (state.hasKey("T") && state.hasKey("V")) {
281 setState_TV(state.convert("T", "K"), state.convert("V", "m^3/kg"));
282 } else if (state.hasKey("H") && state.hasKey("P")) {
283 setState_HP(state.convert("H", "J/kg"), state.convert("P", "Pa"));
284 } else if (state.hasKey("U") && state.hasKey("V")) {
285 setState_UV(state.convert("U", "J/kg"), state.convert("V", "m^3/kg"));
286 } else if (state.hasKey("S") && state.hasKey("P")) {
287 setState_SP(state.convert("S", "J/kg/K"), state.convert("P", "Pa"));
288 } else if (state.hasKey("S") && state.hasKey("V")) {
289 setState_SV(state.convert("S", "J/kg/K"), state.convert("V", "m^3/kg"));
290 } else if (state.hasKey("S") && state.hasKey("T")) {
291 setState_ST(state.convert("S", "J/kg/K"), state.convert("T", "K"));
292 } else if (state.hasKey("P") && state.hasKey("V")) {
293 setState_PV(state.convert("P", "Pa"), state.convert("V", "m^3/kg"));
294 } else if (state.hasKey("U") && state.hasKey("P")) {
295 setState_UP(state.convert("U", "J/kg"), state.convert("P", "Pa"));
296 } else if (state.hasKey("V") && state.hasKey("H")) {
297 setState_VH(state.convert("V", "m^3/kg"), state.convert("H", "J/kg"));
298 } else if (state.hasKey("T") && state.hasKey("H")) {
299 setState_TH(state.convert("T", "K"), state.convert("H", "J/kg"));
300 } else if (state.hasKey("S") && state.hasKey("H")) {
301 setState_SH(state.convert("S", "J/kg/K"), state.convert("H", "J/kg"));
302 } else if (state.hasKey("D") && state.hasKey("P")) {
303 setState_RP(state.convert("D", "kg/m^3"), state.convert("P", "Pa"));
304 } else if (state.hasKey("P") && state.hasKey("Q")) {
305 setState_Psat(state.convert("P", "Pa"), state["Q"].asDouble());
306 } else if (state.hasKey("T") && state.hasKey("Q")) {
307 setState_Tsat(state.convert("T", "K"), state["Q"].asDouble());
308 } else if (state.hasKey("T")) {
309 setState_TP(state.convert("T", "K"), OneAtm);
310 } else if (state.hasKey("P")) {
311 setState_TP(298.15, state.convert("P", "Pa"));
312 } else {
313 throw CanteraError("ThermoPhase::setState",
314 "'state' did not specify a recognized set of properties.\n"
315 "Keys provided were: {}", input_state.keys_str());
316 }
317}
318
319void ThermoPhase::setState_conditional_TP(doublereal t, doublereal p, bool set_p)
320{
322 if (set_p) {
323 setPressure(p);
324 }
325}
326
327void ThermoPhase::setState_HPorUV(double Htarget, double p,
328 double rtol, bool doUV)
329{
330 doublereal dt;
331 doublereal v = 0.0;
332
333 // Assign the specific volume or pressure and make sure it's positive
334 if (doUV) {
335 doublereal v = p;
336 if (v < 1.0E-300) {
337 throw CanteraError("ThermoPhase::setState_HPorUV (UV)",
338 "Input specific volume is too small or negative. v = {}", v);
339 }
340 setDensity(1.0/v);
341 } else {
342 if (p < 1.0E-300) {
343 throw CanteraError("ThermoPhase::setState_HPorUV (HP)",
344 "Input pressure is too small or negative. p = {}", p);
345 }
346 setPressure(p);
347 }
348 double Tmax = maxTemp() + 0.1;
349 double Tmin = minTemp() - 0.1;
350
351 // Make sure we are within the temperature bounds at the start
352 // of the iteration
353 double Tnew = temperature();
354 double Tinit = Tnew;
355 if (Tnew > Tmax) {
356 Tnew = Tmax - 1.0;
357 } else if (Tnew < Tmin) {
358 Tnew = Tmin + 1.0;
359 }
360 if (Tnew != Tinit) {
361 setState_conditional_TP(Tnew, p, !doUV);
362 }
363
364 double Hnew = (doUV) ? intEnergy_mass() : enthalpy_mass();
365 double Cpnew = (doUV) ? cv_mass() : cp_mass();
366 double Htop = Hnew;
367 double Ttop = Tnew;
368 double Hbot = Hnew;
369 double Tbot = Tnew;
370
371 bool ignoreBounds = false;
372 // Unstable phases are those for which cp < 0.0. These are possible for
373 // cases where we have passed the spinodal curve.
374 bool unstablePhase = false;
375 // Counter indicating the last temperature point where the
376 // phase was unstable
377 double Tunstable = -1.0;
378 bool unstablePhaseNew = false;
379
380 // Newton iteration
381 for (int n = 0; n < 500; n++) {
382 double Told = Tnew;
383 double Hold = Hnew;
384 double cpd = Cpnew;
385 if (cpd < 0.0) {
386 unstablePhase = true;
387 Tunstable = Tnew;
388 }
389 // limit step size to 100 K
390 dt = clip((Htarget - Hold)/cpd, -100.0, 100.0);
391
392 // Calculate the new T
393 Tnew = Told + dt;
394
395 // Limit the step size so that we are convergent This is the step that
396 // makes it different from a Newton's algorithm
397 if ((dt > 0.0 && unstablePhase) || (dt <= 0.0 && !unstablePhase)) {
398 if (Hbot < Htarget && Tnew < (0.75 * Tbot + 0.25 * Told)) {
399 dt = 0.75 * (Tbot - Told);
400 Tnew = Told + dt;
401 }
402 } else if (Htop > Htarget && Tnew > (0.75 * Ttop + 0.25 * Told)) {
403 dt = 0.75 * (Ttop - Told);
404 Tnew = Told + dt;
405 }
406
407 // Check Max and Min values
408 if (Tnew > Tmax && !ignoreBounds) {
409 setState_conditional_TP(Tmax, p, !doUV);
410 double Hmax = (doUV) ? intEnergy_mass() : enthalpy_mass();
411 if (Hmax >= Htarget) {
412 if (Htop < Htarget) {
413 Ttop = Tmax;
414 Htop = Hmax;
415 }
416 } else {
417 Tnew = Tmax + 1.0;
418 ignoreBounds = true;
419 }
420 }
421 if (Tnew < Tmin && !ignoreBounds) {
422 setState_conditional_TP(Tmin, p, !doUV);
423 double Hmin = (doUV) ? intEnergy_mass() : enthalpy_mass();
424 if (Hmin <= Htarget) {
425 if (Hbot > Htarget) {
426 Tbot = Tmin;
427 Hbot = Hmin;
428 }
429 } else {
430 Tnew = Tmin - 1.0;
431 ignoreBounds = true;
432 }
433 }
434
435 // Try to keep phase within its region of stability
436 // -> Could do a lot better if I calculate the
437 // spinodal value of H.
438 for (int its = 0; its < 10; its++) {
439 Tnew = Told + dt;
440 if (Tnew < Told / 3.0) {
441 Tnew = Told / 3.0;
442 dt = -2.0 * Told / 3.0;
443 }
444 setState_conditional_TP(Tnew, p, !doUV);
445 if (doUV) {
446 Hnew = intEnergy_mass();
447 Cpnew = cv_mass();
448 } else {
449 Hnew = enthalpy_mass();
450 Cpnew = cp_mass();
451 }
452 if (Cpnew < 0.0) {
453 unstablePhaseNew = true;
454 Tunstable = Tnew;
455 } else {
456 unstablePhaseNew = false;
457 break;
458 }
459 if (unstablePhase == false && unstablePhaseNew == true) {
460 dt *= 0.25;
461 }
462 }
463
464 if (Hnew == Htarget) {
465 return;
466 } else if (Hnew > Htarget && (Htop < Htarget || Hnew < Htop)) {
467 Htop = Hnew;
468 Ttop = Tnew;
469 } else if (Hnew < Htarget && (Hbot > Htarget || Hnew > Hbot)) {
470 Hbot = Hnew;
471 Tbot = Tnew;
472 }
473 // Convergence in H
474 double Herr = Htarget - Hnew;
475 double acpd = std::max(fabs(cpd), 1.0E-5);
476 double denom = std::max(fabs(Htarget), acpd * Tnew);
477 double HConvErr = fabs((Herr)/denom);
478 if (HConvErr < rtol || fabs(dt/Tnew) < rtol) {
479 return;
480 }
481 }
482 // We are here when there hasn't been convergence
483
484 // Formulate a detailed error message, since questions seem to arise often
485 // about the lack of convergence.
486 string ErrString = "No convergence in 500 iterations\n";
487 if (doUV) {
488 ErrString += fmt::format(
489 "\tTarget Internal Energy = {}\n"
490 "\tCurrent Specific Volume = {}\n"
491 "\tStarting Temperature = {}\n"
492 "\tCurrent Temperature = {}\n"
493 "\tCurrent Internal Energy = {}\n"
494 "\tCurrent Delta T = {}\n",
495 Htarget, v, Tinit, Tnew, Hnew, dt);
496 } else {
497 ErrString += fmt::format(
498 "\tTarget Enthalpy = {}\n"
499 "\tCurrent Pressure = {}\n"
500 "\tStarting Temperature = {}\n"
501 "\tCurrent Temperature = {}\n"
502 "\tCurrent Enthalpy = {}\n"
503 "\tCurrent Delta T = {}\n",
504 Htarget, p, Tinit, Tnew, Hnew, dt);
505 }
506 if (unstablePhase) {
507 ErrString += fmt::format(
508 "\t - The phase became unstable (Cp < 0) T_unstable_last = {}\n",
509 Tunstable);
510 }
511 if (doUV) {
512 throw CanteraError("ThermoPhase::setState_HPorUV (UV)", ErrString);
513 } else {
514 throw CanteraError("ThermoPhase::setState_HPorUV (HP)", ErrString);
515 }
516}
517
518void ThermoPhase::setState_SP(double Starget, double p, double rtol)
519{
520 setState_SPorSV(Starget, p, rtol, false);
521}
522
523void ThermoPhase::setState_SV(double Starget, double v, double rtol)
524{
525 assertCompressible("setState_SV");
526 setState_SPorSV(Starget, v, rtol, true);
527}
528
529void ThermoPhase::setState_SPorSV(double Starget, double p,
530 double rtol, bool doSV)
531{
532 doublereal v = 0.0;
533 doublereal dt;
534 if (doSV) {
535 v = p;
536 if (v < 1.0E-300) {
537 throw CanteraError("ThermoPhase::setState_SPorSV (SV)",
538 "Input specific volume is too small or negative. v = {}", v);
539 }
540 setDensity(1.0/v);
541 } else {
542 if (p < 1.0E-300) {
543 throw CanteraError("ThermoPhase::setState_SPorSV (SP)",
544 "Input pressure is too small or negative. p = {}", p);
545 }
546 setPressure(p);
547 }
548 double Tmax = maxTemp() + 0.1;
549 double Tmin = minTemp() - 0.1;
550
551 // Make sure we are within the temperature bounds at the start
552 // of the iteration
553 double Tnew = temperature();
554 double Tinit = Tnew;
555 if (Tnew > Tmax) {
556 Tnew = Tmax - 1.0;
557 } else if (Tnew < Tmin) {
558 Tnew = Tmin + 1.0;
559 }
560 if (Tnew != Tinit) {
561 setState_conditional_TP(Tnew, p, !doSV);
562 }
563
564 double Snew = entropy_mass();
565 double Cpnew = (doSV) ? cv_mass() : cp_mass();
566 double Stop = Snew;
567 double Ttop = Tnew;
568 double Sbot = Snew;
569 double Tbot = Tnew;
570
571 bool ignoreBounds = false;
572 // Unstable phases are those for which Cp < 0.0. These are possible for
573 // cases where we have passed the spinodal curve.
574 bool unstablePhase = false;
575 double Tunstable = -1.0;
576 bool unstablePhaseNew = false;
577
578 // Newton iteration
579 for (int n = 0; n < 500; n++) {
580 double Told = Tnew;
581 double Sold = Snew;
582 double cpd = Cpnew;
583 if (cpd < 0.0) {
584 unstablePhase = true;
585 Tunstable = Tnew;
586 }
587 // limit step size to 100 K
588 dt = clip((Starget - Sold)*Told/cpd, -100.0, 100.0);
589 Tnew = Told + dt;
590
591 // Limit the step size so that we are convergent
592 if ((dt > 0.0 && unstablePhase) || (dt <= 0.0 && !unstablePhase)) {
593 if (Sbot < Starget && Tnew < Tbot) {
594 dt = 0.75 * (Tbot - Told);
595 Tnew = Told + dt;
596 }
597 } else if (Stop > Starget && Tnew > Ttop) {
598 dt = 0.75 * (Ttop - Told);
599 Tnew = Told + dt;
600 }
601
602 // Check Max and Min values
603 if (Tnew > Tmax && !ignoreBounds) {
604 setState_conditional_TP(Tmax, p, !doSV);
605 double Smax = entropy_mass();
606 if (Smax >= Starget) {
607 if (Stop < Starget) {
608 Ttop = Tmax;
609 Stop = Smax;
610 }
611 } else {
612 Tnew = Tmax + 1.0;
613 ignoreBounds = true;
614 }
615 } else if (Tnew < Tmin && !ignoreBounds) {
616 setState_conditional_TP(Tmin, p, !doSV);
617 double Smin = entropy_mass();
618 if (Smin <= Starget) {
619 if (Sbot > Starget) {
620 Tbot = Tmin;
621 Sbot = Smin;
622 }
623 } else {
624 Tnew = Tmin - 1.0;
625 ignoreBounds = true;
626 }
627 }
628
629 // Try to keep phase within its region of stability
630 // -> Could do a lot better if I calculate the
631 // spinodal value of H.
632 for (int its = 0; its < 10; its++) {
633 Tnew = Told + dt;
634 setState_conditional_TP(Tnew, p, !doSV);
635 Cpnew = (doSV) ? cv_mass() : cp_mass();
636 Snew = entropy_mass();
637 if (Cpnew < 0.0) {
638 unstablePhaseNew = true;
639 Tunstable = Tnew;
640 } else {
641 unstablePhaseNew = false;
642 break;
643 }
644 if (unstablePhase == false && unstablePhaseNew == true) {
645 dt *= 0.25;
646 }
647 }
648
649 if (Snew == Starget) {
650 return;
651 } else if (Snew > Starget && (Stop < Starget || Snew < Stop)) {
652 Stop = Snew;
653 Ttop = Tnew;
654 } else if (Snew < Starget && (Sbot > Starget || Snew > Sbot)) {
655 Sbot = Snew;
656 Tbot = Tnew;
657 }
658 // Convergence in S
659 double Serr = Starget - Snew;
660 double acpd = std::max(fabs(cpd), 1.0E-5);
661 double denom = std::max(fabs(Starget), acpd * Tnew);
662 double SConvErr = fabs((Serr * Tnew)/denom);
663 if (SConvErr < rtol || fabs(dt/Tnew) < rtol) {
664 return;
665 }
666 }
667 // We are here when there hasn't been convergence
668
669 // Formulate a detailed error message, since questions seem to arise often
670 // about the lack of convergence.
671 string ErrString = "No convergence in 500 iterations\n";
672 if (doSV) {
673 ErrString += fmt::format(
674 "\tTarget Entropy = {}\n"
675 "\tCurrent Specific Volume = {}\n"
676 "\tStarting Temperature = {}\n"
677 "\tCurrent Temperature = {}\n"
678 "\tCurrent Entropy = {}\n"
679 "\tCurrent Delta T = {}\n",
680 Starget, v, Tinit, Tnew, Snew, dt);
681 } else {
682 ErrString += fmt::format(
683 "\tTarget Entropy = {}\n"
684 "\tCurrent Pressure = {}\n"
685 "\tStarting Temperature = {}\n"
686 "\tCurrent Temperature = {}\n"
687 "\tCurrent Entropy = {}\n"
688 "\tCurrent Delta T = {}\n",
689 Starget, p, Tinit, Tnew, Snew, dt);
690 }
691 if (unstablePhase) {
692 ErrString += fmt::format("\t - The phase became unstable (Cp < 0) T_unstable_last = {}\n",
693 Tunstable);
694 }
695 if (doSV) {
696 throw CanteraError("ThermoPhase::setState_SPorSV (SV)", ErrString);
697 } else {
698 throw CanteraError("ThermoPhase::setState_SPorSV (SP)", ErrString);
699 }
700}
701
702double ThermoPhase::o2Required(const double* y) const
703{
704 // indices of fuel elements
705 size_t iC = elementIndex("C");
706 size_t iS = elementIndex("S");
707 size_t iH = elementIndex("H");
708
709 double o2req = 0.0;
710 double sum = 0.0;
711 for (size_t k = 0; k != m_kk; ++k) {
712 sum += y[k];
713 double x = y[k] / molecularWeights()[k];
714 if (iC != npos) {
715 o2req += x * nAtoms(k, iC);
716 }
717 if (iS != npos) {
718 o2req += x * nAtoms(k, iS);
719 }
720 if (iH != npos) {
721 o2req += x * 0.25 * nAtoms(k, iH);
722 }
723 }
724 if (sum == 0.0) {
725 throw CanteraError("ThermoPhase::o2Required",
726 "No composition specified");
727 }
728 return o2req/sum;
729}
730
731double ThermoPhase::o2Present(const double* y) const
732{
733 size_t iO = elementIndex("O");
734 double o2pres = 0.0;
735 double sum = 0.0;
736 for (size_t k = 0; k != m_kk; ++k) {
737 sum += y[k];
738 o2pres += y[k] / molecularWeights()[k] * nAtoms(k, iO);
739 }
740 if (sum == 0.0) {
741 throw CanteraError("ThermoPhase::o2Present",
742 "No composition specified");
743 }
744 return 0.5 * o2pres / sum;
745}
746
748 const compositionMap& oxComp,
749 ThermoBasis basis) const
750{
751 vector_fp fuel(getCompositionFromMap(fuelComp));
753 return stoichAirFuelRatio(fuel.data(), ox.data(), basis);
754}
755
756double ThermoPhase::stoichAirFuelRatio(const std::string& fuelComp,
757 const std::string& oxComp,
758 ThermoBasis basis) const
759{
760 return stoichAirFuelRatio(
761 parseCompString(fuelComp.find(":") != std::string::npos ? fuelComp : fuelComp+":1.0"),
762 parseCompString(oxComp.find(":") != std::string::npos ? oxComp : oxComp+":1.0"),
763 basis);
764}
765
766double ThermoPhase::stoichAirFuelRatio(const double* fuelComp,
767 const double* oxComp,
768 ThermoBasis basis) const
769{
770 vector_fp fuel, ox;
771 if (basis == ThermoBasis::molar) { // convert input compositions to mass fractions
772 fuel.resize(m_kk);
773 ox.resize(m_kk);
774 moleFractionsToMassFractions(fuelComp, fuel.data());
775 moleFractionsToMassFractions(oxComp, ox.data());
776 fuelComp = fuel.data();
777 oxComp = ox.data();
778 }
779
780 double o2_required_fuel = o2Required(fuelComp) - o2Present(fuelComp);
781 double o2_required_ox = o2Required(oxComp) - o2Present(oxComp);
782
783 if (o2_required_fuel < 0.0 || o2_required_ox > 0.0) {
784 throw CanteraError("ThermoPhase::stoichAirFuelRatio",
785 "Fuel composition contains too much oxygen or "
786 "oxidizer contains not enough oxygen. "
787 "Fuel and oxidizer composition mixed up?");
788 }
789
790 if (o2_required_ox == 0.0) {
791 return std::numeric_limits<double>::infinity();
792 }
793
794 return o2_required_fuel / (-o2_required_ox);
795}
796
797void ThermoPhase::setEquivalenceRatio(double phi, const double* fuelComp,
798 const double* oxComp, ThermoBasis basis)
799{
800 if (phi < 0.0) {
801 throw CanteraError("ThermoPhase::setEquivalenceRatio",
802 "Equivalence ratio phi must be >= 0");
803 }
804
805 double p = pressure();
806
807 vector_fp fuel, ox;
808 if (basis == ThermoBasis::molar) { // convert input compositions to mass fractions
809 fuel.resize(m_kk);
810 ox.resize(m_kk);
811 moleFractionsToMassFractions(fuelComp, fuel.data());
812 moleFractionsToMassFractions(oxComp, ox.data());
813 fuelComp = fuel.data();
814 oxComp = ox.data();
815 }
816
817 double AFR_st = stoichAirFuelRatio(fuelComp, oxComp, ThermoBasis::mass);
818
819 double sum_f = std::accumulate(fuelComp, fuelComp+m_kk, 0.0);
820 double sum_o = std::accumulate(oxComp, oxComp+m_kk, 0.0);
821
822 vector_fp y(m_kk);
823 for (size_t k = 0; k != m_kk; ++k) {
824 y[k] = phi * fuelComp[k]/sum_f + AFR_st * oxComp[k]/sum_o;
825 }
826
827 setMassFractions(y.data());
828 setPressure(p);
829}
830
831void ThermoPhase::setEquivalenceRatio(double phi, const std::string& fuelComp,
832 const std::string& oxComp, ThermoBasis basis)
833{
835 parseCompString(fuelComp.find(":") != std::string::npos ? fuelComp : fuelComp+":1.0"),
836 parseCompString(oxComp.find(":") != std::string::npos ? oxComp : oxComp+":1.0"),
837 basis);
838}
839
840void ThermoPhase::setEquivalenceRatio(double phi, const compositionMap& fuelComp,
841 const compositionMap& oxComp, ThermoBasis basis)
842{
843 vector_fp fuel = getCompositionFromMap(fuelComp);
844 vector_fp ox = getCompositionFromMap(oxComp);
845 setEquivalenceRatio(phi, fuel.data(), ox.data(), basis);
846}
847
849{
850 double o2_required = o2Required(massFractions());
851 double o2_present = o2Present(massFractions());
852
853 if (o2_present == 0.0) { // pure fuel
854 return std::numeric_limits<double>::infinity();
855 }
856
857 return o2_required / o2_present;
858}
859
861 const compositionMap& oxComp,
862 ThermoBasis basis) const
863{
864 vector_fp fuel(getCompositionFromMap(fuelComp));
866 return equivalenceRatio(fuel.data(), ox.data(), basis);
867}
868
869double ThermoPhase::equivalenceRatio(const std::string& fuelComp,
870 const std::string& oxComp,
871 ThermoBasis basis) const
872{
873 return equivalenceRatio(
874 parseCompString(fuelComp.find(":") != std::string::npos ? fuelComp : fuelComp+":1.0"),
875 parseCompString(oxComp.find(":") != std::string::npos ? oxComp : oxComp+":1.0"),
876 basis);
877}
878
879double ThermoPhase::equivalenceRatio(const double* fuelComp,
880 const double* oxComp,
881 ThermoBasis basis) const
882{
883 double Z = mixtureFraction(fuelComp, oxComp, basis);
884
885 if (Z == 0.0) {
886 return 0.0; // pure oxidizer
887 }
888
889 if (Z == 1.0) {
890 return std::numeric_limits<double>::infinity(); // pure fuel
891 }
892
893 vector_fp fuel, ox;
894 if (basis == ThermoBasis::molar) { // convert input compositions to mass fractions
895 fuel.resize(m_kk);
896 ox.resize(m_kk);
897 moleFractionsToMassFractions(fuelComp, fuel.data());
898 moleFractionsToMassFractions(oxComp, ox.data());
899 fuelComp = fuel.data();
900 oxComp = ox.data();
901 }
902
903 double AFR_st = stoichAirFuelRatio(fuelComp, oxComp, ThermoBasis::mass);
904
905 return std::max(Z / (1.0 - Z) * AFR_st, 0.0);
906}
907
908void ThermoPhase::setMixtureFraction(double mixFrac, const compositionMap& fuelComp,
909 const compositionMap& oxComp, ThermoBasis basis)
910{
911 vector_fp fuel(getCompositionFromMap(fuelComp));
913 setMixtureFraction(mixFrac, fuel.data(), ox.data(), basis);
914}
915
916void ThermoPhase::setMixtureFraction(double mixFrac, const std::string& fuelComp,
917 const std::string& oxComp, ThermoBasis basis)
918{
919 setMixtureFraction(mixFrac,
920 parseCompString(fuelComp.find(":") != std::string::npos ? fuelComp : fuelComp+":1.0"),
921 parseCompString(oxComp.find(":") != std::string::npos ? oxComp : oxComp+":1.0"),
922 basis);
923}
924
925void ThermoPhase::setMixtureFraction(double mixFrac, const double* fuelComp,
926 const double* oxComp, ThermoBasis basis)
927{
928 if (mixFrac < 0.0 || mixFrac > 1.0) {
929 throw CanteraError("ThermoPhase::setMixtureFraction",
930 "Mixture fraction must be between 0 and 1");
931 }
932
933 vector_fp fuel, ox;
934 if (basis == ThermoBasis::molar) { // convert input compositions to mass fractions
935 fuel.resize(m_kk);
936 ox.resize(m_kk);
937 moleFractionsToMassFractions(fuelComp, fuel.data());
938 moleFractionsToMassFractions(oxComp, ox.data());
939 fuelComp = fuel.data();
940 oxComp = ox.data();
941 }
942
943 double sum_yf = std::accumulate(fuelComp, fuelComp+m_kk, 0.0);
944 double sum_yo = std::accumulate(oxComp, oxComp+m_kk, 0.0);
945
946 if (sum_yf == 0.0 || sum_yo == 0.0) {
947 throw CanteraError("ThermoPhase::setMixtureFraction",
948 "No fuel and/or oxidizer composition specified");
949 }
950
951 double p = pressure();
952
953 vector_fp y(m_kk);
954
955 for (size_t k = 0; k != m_kk; ++k) {
956 y[k] = mixFrac * fuelComp[k]/sum_yf + (1.0-mixFrac) * oxComp[k]/sum_yo;
957 }
958
959 setMassFractions_NoNorm(y.data());
960 setPressure(p);
961}
962
964 const compositionMap& oxComp,
965 ThermoBasis basis,
966 const std::string& element) const
967{
968 vector_fp fuel(getCompositionFromMap(fuelComp));
970 return mixtureFraction(fuel.data(), ox.data(), basis, element);
971}
972
973double ThermoPhase::mixtureFraction(const std::string& fuelComp,
974 const std::string& oxComp,
975 ThermoBasis basis,
976 const std::string& element) const
977{
978 return mixtureFraction(
979 parseCompString(fuelComp.find(":") != std::string::npos ? fuelComp : fuelComp+":1.0"),
980 parseCompString(oxComp.find(":") != std::string::npos ? oxComp : oxComp+":1.0"),
981 basis, element);
982}
983
984double ThermoPhase::mixtureFraction(const double* fuelComp,
985 const double* oxComp,
986 ThermoBasis basis,
987 const std::string& element) const
988{
989 vector_fp fuel, ox;
990 if (basis == ThermoBasis::molar) { // convert input compositions to mass fractions
991 fuel.resize(m_kk);
992 ox.resize(m_kk);
993 moleFractionsToMassFractions(fuelComp, fuel.data());
994 moleFractionsToMassFractions(oxComp, ox.data());
995 fuelComp = fuel.data();
996 oxComp = ox.data();
997 }
998
999 if (element == "Bilger") // compute the mixture fraction based on the Bilger mixture fraction
1000 {
1001 double o2_required_fuel = o2Required(fuelComp) - o2Present(fuelComp);
1002 double o2_required_ox = o2Required(oxComp) - o2Present(oxComp);
1003 double o2_required_mix = o2Required(massFractions()) - o2Present(massFractions());
1004
1005 if (o2_required_fuel < 0.0 || o2_required_ox > 0.0) {
1006 throw CanteraError("ThermoPhase::mixtureFraction",
1007 "Fuel composition contains too much oxygen or "
1008 "oxidizer contains not enough oxygen. "
1009 "Fuel and oxidizer composition mixed up?");
1010 }
1011
1012 double denominator = o2_required_fuel - o2_required_ox;
1013
1014 if (denominator == 0.0) {
1015 throw CanteraError("ThermoPhase::mixtureFraction",
1016 "Fuel and oxidizer have the same composition");
1017 }
1018
1019 double Z = (o2_required_mix - o2_required_ox) / denominator;
1020
1021 return std::min(std::max(Z, 0.0), 1.0);
1022 } else {
1023 // compute the mixture fraction from a single element
1024 double sum_yf = std::accumulate(fuelComp, fuelComp+m_kk, 0.0);
1025 double sum_yo = std::accumulate(oxComp, oxComp+m_kk, 0.0);
1026
1027 if (sum_yf == 0.0 || sum_yo == 0.0) {
1028 throw CanteraError("ThermoPhase::mixtureFraction",
1029 "No fuel and/or oxidizer composition specified");
1030 }
1031
1032 auto elementalFraction = [this](size_t m, const double* y) {
1033 double Z_m = 0.0;
1034 for (size_t k = 0; k != m_kk; ++k) {
1035 Z_m += y[k] / molecularWeight(k) * nAtoms(k, m);
1036 }
1037 return Z_m;
1038 };
1039
1040 size_t m = elementIndex(element);
1041 double Z_m_fuel = elementalFraction(m, fuelComp)/sum_yf;
1042 double Z_m_ox = elementalFraction(m, oxComp)/sum_yo;
1043 double Z_m_mix = elementalFraction(m, massFractions());
1044
1045 if (Z_m_fuel == Z_m_ox) {
1046 throw CanteraError("ThermoPhase::mixtureFraction",
1047 "Fuel and oxidizer have the same composition for element {}",
1048 element);
1049 }
1050 double Z = (Z_m_mix - Z_m_ox) / (Z_m_fuel - Z_m_ox);
1051 return std::min(std::max(Z, 0.0), 1.0);
1052 }
1053}
1054
1056{
1057 return m_spthermo;
1058}
1059
1061{
1062 return m_spthermo;
1063}
1064
1065
1066void ThermoPhase::initThermoFile(const std::string& inputFile,
1067 const std::string& id)
1068{
1069 if (inputFile.empty()) {
1070 // No input file specified - nothing to set up
1071 return;
1072 }
1073 size_t dot = inputFile.find_last_of(".");
1074 string extension;
1075 if (dot != npos) {
1076 extension = inputFile.substr(dot+1);
1077 }
1078
1079 if (extension == "yml" || extension == "yaml") {
1080 AnyMap root = AnyMap::fromYamlFile(inputFile);
1081 auto& phase = root["phases"].getMapWhere("name", id);
1082 setupPhase(*this, phase, root);
1083 } else {
1084 XML_Node* fxml = get_XML_File(inputFile);
1085 XML_Node* fxml_phase = findXMLPhase(fxml, id);
1086 if (!fxml_phase) {
1087 throw CanteraError("ThermoPhase::initThermoFile",
1088 "ERROR: Can not find phase named {} in file"
1089 " named {}", id, inputFile);
1090 }
1091 importPhase(*fxml_phase, this);
1092 }
1093}
1094
1095void ThermoPhase::initThermoXML(XML_Node& phaseNode, const std::string& id)
1096{
1097 if (phaseNode.hasChild("state")) {
1098 setStateFromXML(phaseNode.child("state"));
1099 }
1100}
1101
1103{
1104 // Check to see that all of the species thermo objects have been initialized
1105 if (!m_spthermo.ready(m_kk)) {
1106 throw CanteraError("ThermoPhase::initThermo()",
1107 "Missing species thermo data");
1108 }
1109}
1110
1111void ThermoPhase::setState_TPQ(double T, double P, double Q)
1112{
1113 if (T > critTemperature()) {
1114 if (P > critPressure() || Q == 1) {
1115 setState_TP(T, P);
1116 return;
1117 } else {
1118 throw CanteraError("ThermoPhase::setState_TPQ",
1119 "Temperature ({}), pressure ({}) and vapor fraction ({}) "
1120 "are inconsistent, above the critical temperature.",
1121 T, P, Q);
1122 }
1123 }
1124
1125 double Psat = satPressure(T);
1126 if (std::abs(Psat / P - 1) < 1e-6) {
1127 setState_Tsat(T, Q);
1128 } else if ((Q == 0 && P >= Psat) || (Q == 1 && P <= Psat)) {
1129 setState_TP(T, P);
1130 } else {
1131 throw CanteraError("ThermoPhase::setState_TPQ",
1132 "Temperature ({}), pressure ({}) and vapor fraction ({}) "
1133 "are inconsistent.\nPsat at this T: {}\n"
1134 "Consider specifying the state using two fully independent "
1135 "properties (for example, temperature and density)",
1136 T, P, Q, Psat);
1137 }
1138}
1139
1140bool ThermoPhase::addSpecies(shared_ptr<Species> spec)
1141{
1142 if (!spec->thermo) {
1143 throw CanteraError("ThermoPhase::addSpecies",
1144 "Species {} has no thermo data", spec->name);
1145 }
1146 bool added = Phase::addSpecies(spec);
1147 if (added) {
1148 spec->thermo->validate(spec->name);
1149 m_spthermo.install_STIT(m_kk-1, spec->thermo);
1150 }
1151 return added;
1152}
1153
1154void ThermoPhase::modifySpecies(size_t k, shared_ptr<Species> spec)
1155{
1156 if (!spec->thermo) {
1157 throw CanteraError("ThermoPhase::modifySpecies",
1158 "Species {} has no thermo data", spec->name);
1159 }
1160 Phase::modifySpecies(k, spec);
1161 if (speciesName(k) != spec->name) {
1162 throw CanteraError("ThermoPhase::modifySpecies",
1163 "New species '{}' does not match existing species '{}' at index {}",
1164 spec->name, speciesName(k), k);
1165 }
1166 spec->thermo->validate(spec->name);
1167 m_spthermo.modifySpecies(k, spec->thermo);
1168}
1169
1170void ThermoPhase::saveSpeciesData(const size_t k, const XML_Node* const data)
1171{
1172 if (m_speciesData.size() < (k + 1)) {
1173 m_speciesData.resize(k+1, 0);
1174 }
1175 m_speciesData[k] = new XML_Node(*data);
1176}
1177
1178const std::vector<const XML_Node*> & ThermoPhase::speciesData() const
1179{
1180 if (m_speciesData.size() != m_kk) {
1181 throw CanteraError("ThermoPhase::speciesData",
1182 "m_speciesData is the wrong size");
1183 }
1184 return m_speciesData;
1185}
1186
1187void ThermoPhase::setParameters(int n, doublereal* const c)
1188{
1189 warn_deprecated("ThermoPhase::setParamters(int, double*)",
1190 "To be removed after Cantera 2.6.");
1191}
1192
1193void ThermoPhase::getParameters(int& n, doublereal* const c) const
1194{
1195 warn_deprecated("ThermoPhase::getParamters(int&, double*)",
1196 "To be removed after Cantera 2.6.");
1197}
1198
1199
1200void ThermoPhase::setParameters(const AnyMap& phaseNode, const AnyMap& rootNode)
1201{
1202 m_input = phaseNode;
1203}
1204
1205AnyMap ThermoPhase::parameters(bool withInput) const
1206{
1207 AnyMap out;
1208 getParameters(out);
1209 if (withInput) {
1210 out.update(m_input);
1211 }
1212 return out;
1213}
1214
1216{
1217 phaseNode["name"] = name();
1218 phaseNode["thermo"] = ThermoFactory::factory()->canonicalize(type());
1219 vector<string> elementNames;
1220 for (size_t i = 0; i < nElements(); i++) {
1221 elementNames.push_back(elementName(i));
1222 }
1223 phaseNode["elements"] = elementNames;
1224 phaseNode["species"] = speciesNames();
1225
1226 AnyMap state;
1227 auto stateVars = nativeState();
1228 if (stateVars.count("T")) {
1229 state["T"].setQuantity(temperature(), "K");
1230 }
1231
1232 if (stateVars.count("D")) {
1233 state["density"].setQuantity(density(), "kg/m^3");
1234 } else if (stateVars.count("P")) {
1235 state["P"].setQuantity(pressure(), "Pa");
1236 }
1237
1238 if (stateVars.count("Y")) {
1239 map<string, double> Y;
1240 for (size_t k = 0; k < m_kk; k++) {
1241 double Yk = massFraction(k);
1242 if (Yk > 0) {
1243 Y[speciesName(k)] = Yk;
1244 }
1245 }
1246 state["Y"] = Y;
1247 state["Y"].setFlowStyle();
1248 } else if (stateVars.count("X")) {
1249 map<string, double> X;
1250 for (size_t k = 0; k < m_kk; k++) {
1251 double Xk = moleFraction(k);
1252 if (Xk > 0) {
1253 X[speciesName(k)] = Xk;
1254 }
1255 }
1256 state["X"] = X;
1257 state["X"].setFlowStyle();
1258 }
1259
1260 phaseNode["state"] = std::move(state);
1261
1262 static bool reg = AnyMap::addOrderingRules("Phase", {{"tail", "state"}});
1263 if (reg) {
1264 phaseNode["__type__"] = "Phase";
1265 }
1266}
1267
1269{
1270 return m_input;
1271}
1272
1274{
1275 return m_input;
1276}
1277
1279{
1280 string comp = getChildValue(state,"moleFractions");
1281 if (comp != "") {
1283 } else {
1284 comp = getChildValue(state,"massFractions");
1285 if (comp != "") {
1287 }
1288 }
1289 if (state.hasChild("temperature")) {
1290 double t = getFloat(state, "temperature", "temperature");
1291 setTemperature(t);
1292 }
1293 if (state.hasChild("pressure")) {
1294 double p = getFloat(state, "pressure", "pressure");
1295 setPressure(p);
1296 }
1297 if (state.hasChild("density")) {
1298 double rho = getFloat(state, "density", "density");
1299 setDensity(rho);
1300 }
1301}
1302
1305 m_tlast += 0.1234;
1306}
1307
1308void ThermoPhase::equilibrate(const std::string& XY, const std::string& solver,
1309 double rtol, int max_steps, int max_iter,
1310 int estimate_equil, int log_level)
1311{
1312 if (solver == "auto" || solver == "element_potential") {
1313 vector_fp initial_state;
1314 saveState(initial_state);
1315 debuglog("Trying ChemEquil solver\n", log_level);
1316 try {
1317 ChemEquil E;
1318 E.options.maxIterations = max_steps;
1319 E.options.relTolerance = rtol;
1320 int ret = E.equilibrate(*this, XY.c_str(), log_level-1);
1321 if (ret < 0) {
1322 throw CanteraError("ThermoPhase::equilibrate",
1323 "ChemEquil solver failed. Return code: {}", ret);
1324 }
1325 debuglog("ChemEquil solver succeeded\n", log_level);
1326 return;
1327 } catch (std::exception& err) {
1328 debuglog("ChemEquil solver failed.\n", log_level);
1329 debuglog(err.what(), log_level);
1330 restoreState(initial_state);
1331 if (solver == "auto") {
1332 } else {
1333 throw;
1334 }
1335 }
1336 }
1337
1338 if (solver == "auto" || solver == "vcs" || solver == "gibbs") {
1339 MultiPhase M;
1340 M.addPhase(this, 1.0);
1341 M.init();
1342 M.equilibrate(XY, solver, rtol, max_steps, max_iter,
1343 estimate_equil, log_level);
1344 return;
1345 }
1346
1347 if (solver != "auto") {
1348 throw CanteraError("ThermoPhase::equilibrate",
1349 "Invalid solver specified: '{}'", solver);
1350 }
1351}
1352
1353void ThermoPhase::getdlnActCoeffdlnN(const size_t ld, doublereal* const dlnActCoeffdlnN)
1354{
1355 for (size_t m = 0; m < m_kk; m++) {
1356 for (size_t k = 0; k < m_kk; k++) {
1357 dlnActCoeffdlnN[ld * k + m] = 0.0;
1358 }
1359 }
1360 return;
1361}
1362
1363void ThermoPhase::getdlnActCoeffdlnN_numderiv(const size_t ld, doublereal* const dlnActCoeffdlnN)
1364{
1365 double deltaMoles_j = 0.0;
1366 double pres = pressure();
1367
1368 // Evaluate the current base activity coefficients if necessary
1369 vector_fp ActCoeff_Base(m_kk);
1370 getActivityCoefficients(ActCoeff_Base.data());
1371 vector_fp Xmol_Base(m_kk);
1372 getMoleFractions(Xmol_Base.data());
1373
1374 // Make copies of ActCoeff and Xmol_ for use in taking differences
1375 vector_fp ActCoeff(m_kk);
1376 vector_fp Xmol(m_kk);
1377 double v_totalMoles = 1.0;
1378 double TMoles_base = v_totalMoles;
1379
1380 // Loop over the columns species to be deltad
1381 for (size_t j = 0; j < m_kk; j++) {
1382 // Calculate a value for the delta moles of species j
1383 // -> Note Xmol_[] and Tmoles are always positive or zero quantities.
1384 // -> experience has shown that you always need to make the deltas
1385 // greater than needed to change the other mole fractions in order
1386 // to capture some effects.
1387 double moles_j_base = v_totalMoles * Xmol_Base[j];
1388 deltaMoles_j = 1.0E-7 * moles_j_base + v_totalMoles * 1.0E-13 + 1.0E-150;
1389
1390 // Now, update the total moles in the phase and all of the mole
1391 // fractions based on this.
1392 v_totalMoles = TMoles_base + deltaMoles_j;
1393 for (size_t k = 0; k < m_kk; k++) {
1394 Xmol[k] = Xmol_Base[k] * TMoles_base / v_totalMoles;
1395 }
1396 Xmol[j] = (moles_j_base + deltaMoles_j) / v_totalMoles;
1397
1398 // Go get new values for the activity coefficients.
1399 // -> Note this calls setState_PX();
1400 setState_PX(pres, Xmol.data());
1401 getActivityCoefficients(ActCoeff.data());
1402
1403 // Calculate the column of the matrix
1404 double* const lnActCoeffCol = dlnActCoeffdlnN + ld * j;
1405 for (size_t k = 0; k < m_kk; k++) {
1406 lnActCoeffCol[k] = (2*moles_j_base + deltaMoles_j) *(ActCoeff[k] - ActCoeff_Base[k]) /
1407 ((ActCoeff[k] + ActCoeff_Base[k]) * deltaMoles_j);
1408 }
1409 // Revert to the base case Xmol_, v_totalMoles
1410 v_totalMoles = TMoles_base;
1411 Xmol = Xmol_Base;
1412 }
1413
1414 setState_PX(pres, Xmol_Base.data());
1415}
1416
1417std::string ThermoPhase::report(bool show_thermo, doublereal threshold) const
1418{
1419 if (type() == "None") {
1420 throw NotImplementedError("ThermoPhase::report",
1421 "Not implemented for thermo model 'None'");
1422 }
1423
1424 fmt::memory_buffer b;
1425 // This is the width of the first column of names in the report.
1426 int name_width = 18;
1427
1428 string blank_leader = fmt::format("{:{}}", "", name_width);
1429
1430 string string_property = fmt::format("{{:>{}}} {{}}\n", name_width);
1431
1432 string one_property = fmt::format("{{:>{}}} {{:<.5g}} {{}}\n", name_width);
1433
1434 string two_prop_header = "{} {:^15} {:^15}\n";
1435 string kg_kmol_header = fmt::format(
1436 two_prop_header, blank_leader, "1 kg", "1 kmol"
1437 );
1438 string Y_X_header = fmt::format(
1439 two_prop_header, blank_leader, "mass frac. Y", "mole frac. X"
1440 );
1441 string two_prop_sep = fmt::format(
1442 "{} {:-^15} {:-^15}\n", blank_leader, "", ""
1443 );
1444 string two_property = fmt::format(
1445 "{{:>{}}} {{:15.5g}} {{:15.5g}} {{}}\n", name_width
1446 );
1447
1448 string three_prop_header = fmt::format(
1449 "{} {:^15} {:^15} {:^15}\n", blank_leader, "mass frac. Y",
1450 "mole frac. X", "chem. pot. / RT"
1451 );
1452 string three_prop_sep = fmt::format(
1453 "{} {:-^15} {:-^15} {:-^15}\n", blank_leader, "", "", ""
1454 );
1455 string three_property = fmt::format(
1456 "{{:>{}}} {{:15.5g}} {{:15.5g}} {{:15.5g}}\n", name_width
1457 );
1458
1459 try {
1460 if (name() != "") {
1461 fmt_append(b, "\n {}:\n", name());
1462 }
1463 fmt_append(b, "\n");
1464 fmt_append(b, one_property, "temperature", temperature(), "K");
1465 fmt_append(b, one_property, "pressure", pressure(), "Pa");
1466 fmt_append(b, one_property, "density", density(), "kg/m^3");
1467 fmt_append(b, one_property,
1468 "mean mol. weight", meanMolecularWeight(), "kg/kmol");
1469
1470 double phi = electricPotential();
1471 if (phi != 0.0) {
1472 fmt_append(b, one_property, "potential", phi, "V");
1473 }
1474
1475 fmt_append(b, string_property, "phase of matter", phaseOfMatter());
1476
1477 if (show_thermo) {
1478 fmt_append(b, "\n");
1479 fmt_append(b, kg_kmol_header);
1480 fmt_append(b, two_prop_sep);
1481 fmt_append(b, two_property,
1482 "enthalpy", enthalpy_mass(), enthalpy_mole(), "J");
1483 fmt_append(b, two_property,
1484 "internal energy", intEnergy_mass(), intEnergy_mole(), "J");
1485 fmt_append(b, two_property,
1486 "entropy", entropy_mass(), entropy_mole(), "J/K");
1487 fmt_append(b, two_property,
1488 "Gibbs function", gibbs_mass(), gibbs_mole(), "J");
1489 fmt_append(b, two_property,
1490 "heat capacity c_p", cp_mass(), cp_mole(), "J/K");
1491 try {
1492 fmt_append(b, two_property,
1493 "heat capacity c_v", cv_mass(), cv_mole(), "J/K");
1494 } catch (NotImplementedError&) {
1495 fmt_append(b, string_property,
1496 "heat capacity c_v", "<not implemented>");
1497 }
1498 }
1499
1500 vector_fp x(m_kk);
1501 vector_fp y(m_kk);
1502 vector_fp mu(m_kk);
1503 getMoleFractions(&x[0]);
1504 getMassFractions(&y[0]);
1505 getChemPotentials(&mu[0]);
1506 int nMinor = 0;
1507 double xMinor = 0.0;
1508 double yMinor = 0.0;
1509 fmt_append(b, "\n");
1510 if (show_thermo) {
1511 fmt_append(b, three_prop_header);
1512 fmt_append(b, three_prop_sep);
1513 for (size_t k = 0; k < m_kk; k++) {
1514 if (abs(x[k]) >= threshold) {
1515 if (abs(x[k]) > SmallNumber) {
1516 fmt_append(b, three_property,
1517 speciesName(k), y[k], x[k], mu[k]/RT());
1518 } else {
1519 fmt_append(b, two_property, speciesName(k), y[k], x[k], "");
1520 }
1521 } else {
1522 nMinor++;
1523 xMinor += x[k];
1524 yMinor += y[k];
1525 }
1526 }
1527 } else {
1528 fmt_append(b, Y_X_header);
1529 fmt_append(b, two_prop_sep);
1530 for (size_t k = 0; k < m_kk; k++) {
1531 if (abs(x[k]) >= threshold) {
1532 fmt_append(b, two_property, speciesName(k), y[k], x[k], "");
1533 } else {
1534 nMinor++;
1535 xMinor += x[k];
1536 yMinor += y[k];
1537 }
1538 }
1539 }
1540 if (nMinor) {
1541 string minor = fmt::format("[{:+5d} minor]", nMinor);
1542 fmt_append(b, two_property, minor, yMinor, xMinor, "");
1543 }
1544 } catch (CanteraError& err) {
1545 return to_string(b) + err.what();
1546 }
1547 return to_string(b);
1548}
1549
1550void ThermoPhase::reportCSV(std::ofstream& csvFile) const
1551{
1552 int tabS = 15;
1553 int tabM = 30;
1554 csvFile.precision(8);
1555 vector_fp X(nSpecies());
1556 getMoleFractions(&X[0]);
1557 std::vector<std::string> pNames;
1558 std::vector<vector_fp> data;
1559 getCsvReportData(pNames, data);
1560
1561 csvFile << setw(tabS) << "Species,";
1562 for (size_t i = 0; i < pNames.size(); i++) {
1563 csvFile << setw(tabM) << pNames[i] << ",";
1564 }
1565 csvFile << endl;
1566 for (size_t k = 0; k < nSpecies(); k++) {
1567 csvFile << setw(tabS) << speciesName(k) + ",";
1568 if (X[k] > SmallNumber) {
1569 for (size_t i = 0; i < pNames.size(); i++) {
1570 csvFile << setw(tabM) << data[i][k] << ",";
1571 }
1572 csvFile << endl;
1573 } else {
1574 for (size_t i = 0; i < pNames.size(); i++) {
1575 csvFile << setw(tabM) << 0 << ",";
1576 }
1577 csvFile << endl;
1578 }
1579 }
1580}
1581
1582void ThermoPhase::getCsvReportData(std::vector<std::string>& names,
1583 std::vector<vector_fp>& data) const
1584{
1585 names.clear();
1586 data.assign(10, vector_fp(nSpecies()));
1587
1588 names.push_back("X");
1589 getMoleFractions(&data[0][0]);
1590
1591 names.push_back("Y");
1592 getMassFractions(&data[1][0]);
1593
1594 names.push_back("Chem. Pot (J/kmol)");
1595 getChemPotentials(&data[2][0]);
1596
1597 names.push_back("Activity");
1598 getActivities(&data[3][0]);
1599
1600 names.push_back("Act. Coeff.");
1601 getActivityCoefficients(&data[4][0]);
1602
1603 names.push_back("Part. Mol Enthalpy (J/kmol)");
1604 getPartialMolarEnthalpies(&data[5][0]);
1605
1606 names.push_back("Part. Mol. Entropy (J/K/kmol)");
1607 getPartialMolarEntropies(&data[6][0]);
1608
1609 names.push_back("Part. Mol. Energy (J/kmol)");
1610 getPartialMolarIntEnergies(&data[7][0]);
1611
1612 names.push_back("Part. Mol. Cp (J/K/kmol");
1613 getPartialMolarCp(&data[8][0]);
1614
1615 names.push_back("Part. Mol. Cv (J/K/kmol)");
1616 getPartialMolarVolumes(&data[9][0]);
1617}
1618
1619}
Chemical equilibrium.
Headers for the MultiPhase object that is used to set up multiphase equilibrium problems (see Classes...
Pure Virtual Base class for individual species reference state thermodynamic managers and text for th...
Declaration for class Cantera::Species.
Headers for the factory class that can create known ThermoPhase objects (see Thermodynamic Properties...
Header file for class ThermoPhase, the base class for phases with thermodynamic properties,...
A map of string keys to values whose type can vary at runtime.
Definition: AnyMap.h:399
size_t size() const
Returns the number of elements in this map.
Definition: AnyMap.h:590
double convert(const std::string &key, const std::string &units) const
Convert the item stored by the given key to the units specified in units.
Definition: AnyMap.cpp:1508
static AnyMap fromYamlFile(const std::string &name, const std::string &parent_name="")
Create an AnyMap from a YAML file.
Definition: AnyMap.cpp:1743
void erase(const std::string &key)
Erase the value held by key.
Definition: AnyMap.cpp:1411
static bool addOrderingRules(const std::string &objectType, const std::vector< std::vector< std::string > > &specs)
Add global rules for setting the order of elements when outputting AnyMap objects to YAML.
Definition: AnyMap.cpp:1702
void setFlowStyle(bool flow=true)
Use "flow" style when outputting this AnyMap to YAML.
Definition: AnyMap.cpp:1698
std::string keys_str() const
Return a string listing the keys in this AnyMap, for use in error messages, for example.
Definition: AnyMap.cpp:1430
bool hasKey(const std::string &key) const
Returns true if the map contains an item named key.
Definition: AnyMap.cpp:1406
void update(const AnyMap &other, bool keepExisting=true)
Add items from other to this AnyMap.
Definition: AnyMap.cpp:1421
Base class for exceptions thrown by Cantera classes.
Definition: ctexceptions.h:61
const char * what() const
Get a description of the error.
Class ChemEquil implements a chemical equilibrium solver for single-phase solutions.
Definition: ChemEquil.h:81
int equilibrate(ThermoPhase &s, const char *XY, int loglevel=0)
Definition: ChemEquil.cpp:309
EquilOpt options
Options controlling how the calculation is carried out.
Definition: ChemEquil.h:129
doublereal relTolerance
Relative tolerance.
Definition: ChemEquil.h:32
int maxIterations
Maximum number of iterations.
Definition: ChemEquil.h:34
std::string canonicalize(const std::string &name)
Get the canonical name registered for a type.
Definition: FactoryBase.h:95
A class for multiphase mixtures.
Definition: MultiPhase.h:60
void init()
Process phases and build atomic composition array.
Definition: MultiPhase.cpp:118
void addPhase(ThermoPhase *p, doublereal moles)
Add a phase to the mixture.
Definition: MultiPhase.cpp:51
A species thermodynamic property manager for a phase.
bool ready(size_t nSpecies)
Check if data for all species (0 through nSpecies-1) has been installed.
virtual void install_STIT(size_t index, shared_ptr< SpeciesThermoInterpType > stit)
Install a new species thermodynamic property parameterization for one species.
virtual void modifySpecies(size_t index, shared_ptr< SpeciesThermoInterpType > spec)
Modify the species thermodynamic property parameterization for a species.
virtual void resetHf298(const size_t k)
Restore the original heat of formation of one or more species.
An error indicating that an unimplemented function has been called.
Definition: ctexceptions.h:187
double massFraction(size_t k) const
Return the mass fraction of a single species.
Definition: Phase.cpp:569
virtual bool addSpecies(shared_ptr< Species > spec)
Add a Species to this Phase.
Definition: Phase.cpp:803
virtual void setMoleFractions(const double *const x)
Set the mole fractions to the specified values.
Definition: Phase.cpp:339
std::string name() const
Return the name of the phase.
Definition: Phase.cpp:70
size_t nSpecies() const
Returns the number of species in the phase.
Definition: Phase.h:273
void setMoleFractionsByName(const compositionMap &xMap)
Set the species mole fractions by name.
Definition: Phase.cpp:380
doublereal charge(size_t k) const
Dimensionless electrical charge of a single molecule of species k The charge is normalized by the the...
Definition: Phase.h:630
virtual void setMassFractions_NoNorm(const double *const y)
Set the mass fractions to the specified values without normalizing.
Definition: Phase.cpp:405
void assertCompressible(const std::string &setter) const
Ensure that phase is compressible.
Definition: Phase.h:903
vector_fp getCompositionFromMap(const compositionMap &comp) const
Converts a compositionMap to a vector with entries for each species Species that are not specified ar...
Definition: Phase.cpp:1008
size_t m_kk
Number of species in the phase.
Definition: Phase.h:943
virtual void modifySpecies(size_t k, shared_ptr< Species > spec)
Modify the thermodynamic data associated with a species.
Definition: Phase.cpp:899
size_t nDim() const
Returns the number of spatial dimensions (1, 2, or 3)
Definition: Phase.h:638
void saveState(vector_fp &state) const
Save the current internal state of the phase.
Definition: Phase.cpp:286
virtual std::map< std::string, size_t > nativeState() const
Return a map of properties defining the native state of a substance.
Definition: Phase.cpp:230
const vector_fp & molecularWeights() const
Return a const reference to the internal vector of molecular weights.
Definition: Phase.cpp:509
virtual void setPressure(double p)
Set the internally stored pressure (Pa) at constant temperature and composition.
Definition: Phase.h:712
void moleFractionsToMassFractions(const double *X, double *Y) const
Converts a mixture composition from mass fractions to mole fractions.
Definition: Phase.cpp:1037
size_t elementIndex(const std::string &name) const
Return the index of element named 'name'.
Definition: Phase.cpp:106
doublereal molecularWeight(size_t k) const
Molecular weight of species k.
Definition: Phase.cpp:492
std::string speciesName(size_t k) const
Name of the species with index k.
Definition: Phase.cpp:200
virtual void setDensity(const double density_)
Set the internally stored density (kg/m^3) of the phase.
Definition: Phase.cpp:687
doublereal meanMolecularWeight() const
The mean molecular weight. Units: (kg/kmol)
Definition: Phase.h:751
void getMoleFractions(double *const x) const
Get the species mole fraction vector.
Definition: Phase.cpp:543
const double * massFractions() const
Return a const pointer to the mass fraction array.
Definition: Phase.h:532
double moleFraction(size_t k) const
Return the mole fraction of a single species.
Definition: Phase.cpp:548
void setState_TR(doublereal t, doublereal rho)
Set the internally stored temperature (K) and density (kg/m^3)
Definition: Phase.cpp:462
doublereal nAtoms(size_t k, size_t m) const
Number of atoms of element m in species k.
Definition: Phase.cpp:154
const std::vector< std::string > & elementNames() const
Return a read-only reference to the vector of element names.
Definition: Phase.cpp:116
virtual double density() const
Density (kg/m^3).
Definition: Phase.h:679
doublereal temperature() const
Temperature (K).
Definition: Phase.h:654
virtual void setTemperature(double temp)
Set the internally stored temperature of the phase (K).
Definition: Phase.h:719
size_t nElements() const
Number of elements.
Definition: Phase.cpp:81
virtual void setMassFractions(const double *const y)
Set the mass fractions to the specified values and normalize them.
Definition: Phase.cpp:391
void restoreState(const vector_fp &state)
Restore a state saved on a previous call to saveState.
Definition: Phase.cpp:310
const std::vector< std::string > & speciesNames() const
Return a const reference to the vector of species names.
Definition: Phase.cpp:206
virtual void invalidateCache()
Invalidate any cached values which are normally updated only when a change in state is detected.
Definition: Phase.cpp:984
void setMassFractionsByName(const compositionMap &yMap)
Set the species mass fractions by name.
Definition: Phase.cpp:416
void getMassFractions(double *const y) const
Get the species mass fractions.
Definition: Phase.cpp:585
virtual double pressure() const
Return the thermodynamic pressure (Pa).
Definition: Phase.h:672
std::string elementName(size_t m) const
Name of the element with index m.
Definition: Phase.cpp:100
static ThermoFactory * factory()
Static function that creates a static instance of the factory.
Definition: ThermoFactory.h:63
virtual void setStateFromXML(const XML_Node &state)
Set the initial state of the phase to the conditions specified in the state XML element.
int m_ssConvention
Contains the standard state convention.
Definition: ThermoPhase.h:1925
virtual std::string report(bool show_thermo=true, doublereal threshold=-1e-14) const
returns a summary of the state of the phase as a string
virtual void setState_TPY(doublereal t, doublereal p, const doublereal *y)
Set the internally stored temperature (K), pressure (Pa), and mass fractions of the phase.
virtual void getPartialMolarEntropies(doublereal *sbar) const
Returns an array of partial molar entropies of the species in the solution.
Definition: ThermoPhase.h:531
virtual void setState_PY(doublereal p, doublereal *y)
Set the internally stored pressure (Pa) and mass fractions.
virtual void setState_HP(double h, double p, double tol=1e-9)
Set the internally stored specific enthalpy (J/kg) and pressure (Pa) of the phase.
virtual doublereal gibbs_mole() const
Molar Gibbs function. Units: J/kmol.
Definition: ThermoPhase.h:254
virtual void setState_UV(double u, double v, double tol=1e-9)
Set the specific internal energy (J/kg) and specific volume (m^3/kg).
virtual bool addSpecies(shared_ptr< Species > spec)
double equivalenceRatio() const
Compute the equivalence ratio for the current mixture from available oxygen and required oxygen.
doublereal entropy_mass() const
Specific entropy. Units: J/kg/K.
Definition: ThermoPhase.h:758
virtual void setState_TP(doublereal t, doublereal p)
Set the temperature (K) and pressure (Pa)
virtual doublereal critPressure() const
Critical pressure (Pa).
Definition: ThermoPhase.h:1489
virtual void getPartialMolarEnthalpies(doublereal *hbar) const
Returns an array of partial molar enthalpies for the species in the mixture.
Definition: ThermoPhase.h:521
doublereal RT() const
Return the Gas Constant multiplied by the current temperature.
Definition: ThermoPhase.h:782
virtual void getActivities(doublereal *a) const
Get the array of non-dimensional activities at the current solution temperature, pressure,...
Definition: ThermoPhase.cpp:77
virtual void getLnActivityCoefficients(doublereal *lnac) const
Get the array of non-dimensional molar-based ln activity coefficients at the current solution tempera...
Definition: ThermoPhase.cpp:85
doublereal m_tlast
last value of the temperature processed by reference state
Definition: ThermoPhase.h:1928
virtual doublereal critTemperature() const
Critical temperature (K).
Definition: ThermoPhase.h:1484
virtual void setState_TV(double t, double v, double tol=1e-9)
Set the temperature (K) and specific volume (m^3/kg).
Definition: ThermoPhase.h:981
double o2Present(const double *y) const
Helper function for computing the amount of oxygen available in the current mixture.
virtual void setState_Tsat(doublereal t, doublereal x)
Set the state to a saturated system at a particular temperature.
Definition: ThermoPhase.h:1543
virtual void setState_PV(double p, double v, double tol=1e-9)
Set the pressure (Pa) and specific volume (m^3/kg).
Definition: ThermoPhase.h:997
virtual doublereal satPressure(doublereal t)
Return the saturation pressure given the temperature.
Definition: ThermoPhase.h:1529
virtual void setState(const AnyMap &state)
Set the state using an AnyMap containing any combination of properties supported by the thermodynamic...
void setState_SPorSV(double s, double p, double tol=1e-9, bool doSV=false)
Carry out work in SP and SV calculations.
void setState_HPorUV(doublereal h, doublereal p, doublereal tol=1e-9, bool doUV=false)
Carry out work in HP and UV calculations.
virtual void getChemPotentials(doublereal *mu) const
Get the species chemical potentials. Units: J/kmol.
Definition: ThermoPhase.h:495
virtual void getActivityCoefficients(doublereal *ac) const
Get the array of non-dimensional molar-based activity coefficients at the current solution temperatur...
Definition: ThermoPhase.h:454
void initThermoFile(const std::string &inputFile, const std::string &id)
virtual void initThermoXML(XML_Node &phaseNode, const std::string &id)
Import and initialize a ThermoPhase object using an XML tree.
doublereal gibbs_mass() const
Specific Gibbs function. Units: J/kg.
Definition: ThermoPhase.h:763
virtual doublereal logStandardConc(size_t k=0) const
Natural logarithm of the standard concentration of the kth species.
Definition: ThermoPhase.cpp:72
virtual void modifySpecies(size_t k, shared_ptr< Species > spec)
Modify the thermodynamic data associated with a species.
virtual void getdlnActCoeffdlnN(const size_t ld, doublereal *const dlnActCoeffdlnN)
Get the array of derivatives of the log activity coefficients with respect to the log of the species ...
virtual void setState_ST(double s, double t, double tol=1e-9)
Set the specific entropy (J/kg/K) and temperature (K).
Definition: ThermoPhase.h:965
double stoichAirFuelRatio(const double *fuelComp, const double *oxComp, ThermoBasis basis=ThermoBasis::molar) const
Compute the stoichiometric air to fuel ratio (kg oxidizer / kg fuel) given fuel and oxidizer composit...
virtual doublereal entropy_mole() const
Molar entropy. Units: J/kmol/K.
Definition: ThermoPhase.h:249
AnyMap parameters(bool withInput=true) const
Returns the parameters of a ThermoPhase object such that an identical one could be reconstructed usin...
virtual void setState_RPY(doublereal rho, doublereal p, const doublereal *y)
Set the density (kg/m**3), pressure (Pa) and mass fractions.
virtual void setState_TPX(doublereal t, doublereal p, const doublereal *x)
Set the temperature (K), pressure (Pa), and mole fractions.
const std::vector< const XML_Node * > & speciesData() const
Return a pointer to the vector of XML nodes containing the species data for this phase.
virtual void getPartialMolarVolumes(doublereal *vbar) const
Return an array of partial molar volumes for the species in the mixture.
Definition: ThermoPhase.h:562
doublereal cp_mass() const
Specific heat at constant pressure. Units: J/kg/K.
Definition: ThermoPhase.h:768
virtual void getPartialMolarCp(doublereal *cpbar) const
Return an array of partial molar heat capacities for the species in the mixture.
Definition: ThermoPhase.h:552
virtual void getCsvReportData(std::vector< std::string > &names, std::vector< vector_fp > &data) const
Fills names and data with the column names and species thermo properties to be included in the output...
virtual doublereal cp_mole() const
Molar heat capacity at constant pressure. Units: J/kmol/K.
Definition: ThermoPhase.h:259
virtual void setState_PX(doublereal p, doublereal *x)
Set the pressure (Pa) and mole fractions.
virtual std::string phaseOfMatter() const
String indicating the mechanical phase of the matter in this Phase.
Definition: ThermoPhase.h:142
double o2Required(const double *y) const
Helper function for computing the amount of oxygen required for complete oxidation.
virtual doublereal cv_mole() const
Molar heat capacity at constant volume. Units: J/kmol/K.
Definition: ThermoPhase.h:264
ThermoPhase()
Constructor.
Definition: ThermoPhase.cpp:29
virtual doublereal intEnergy_mole() const
Molar internal energy. Units: J/kmol.
Definition: ThermoPhase.h:244
virtual void getActivityConcentrations(doublereal *c) const
This method returns an array of generalized concentrations.
Definition: ThermoPhase.h:404
virtual void getPartialMolarIntEnergies(doublereal *ubar) const
Return an array of partial molar internal energies for the species in the mixture.
Definition: ThermoPhase.h:541
virtual int activityConvention() const
This method returns the convention used in specification of the activities, of which there are curren...
Definition: ThermoPhase.cpp:56
virtual void initThermo()
Initialize the ThermoPhase object after all species have been set up.
virtual doublereal standardConcentration(size_t k=0) const
Return the standard concentration for the kth species.
Definition: ThermoPhase.h:425
void saveSpeciesData(const size_t k, const XML_Node *const data)
Store a reference pointer to the XML tree containing the species data for this phase.
virtual MultiSpeciesThermo & speciesThermo(int k=-1)
Return a changeable reference to the calculation manager for species reference-state thermodynamic pr...
virtual void setState_UP(double u, double p, double tol=1e-9)
Set the specific internal energy (J/kg) and pressure (Pa).
Definition: ThermoPhase.h:1013
virtual void setState_SP(double s, double p, double tol=1e-9)
Set the specific entropy (J/kg/K) and pressure (Pa).
virtual int standardStateConvention() const
This method returns the convention used in specification of the standard state, of which there are cu...
Definition: ThermoPhase.cpp:61
virtual doublereal maxTemp(size_t k=npos) const
Maximum temperature for which the thermodynamic data for the species are valid.
Definition: ThermoPhase.h:218
virtual void setState_SH(double s, double h, double tol=1e-9)
Set the specific entropy (J/kg/K) and the specific enthalpy (J/kg)
Definition: ThermoPhase.h:1061
void getElectrochemPotentials(doublereal *mu) const
Get the species electrochemical potentials.
Definition: ThermoPhase.cpp:93
virtual std::string type() const
String indicating the thermodynamic model implemented.
Definition: ThermoPhase.h:113
doublereal cv_mass() const
Specific heat at constant volume. Units: J/kg/K.
Definition: ThermoPhase.h:773
virtual void setState_RP(doublereal rho, doublereal p)
Set the density (kg/m**3) and pressure (Pa) at constant composition.
Definition: ThermoPhase.h:1078
void setMixtureFraction(double mixFrac, const double *fuelComp, const double *oxComp, ThermoBasis basis=ThermoBasis::molar)
Set the mixture composition according to the mixture fraction = kg fuel / (kg oxidizer + kg fuel)
virtual void resetHf298(const size_t k=npos)
Restore the original heat of formation of one or more species.
Definition: ThermoPhase.cpp:45
virtual void setState_TH(double t, double h, double tol=1e-9)
Set the temperature (K) and the specific enthalpy (J/kg)
Definition: ThermoPhase.h:1045
virtual Units standardConcentrationUnits() const
Returns the units of the "standard concentration" for this phase.
Definition: ThermoPhase.cpp:66
virtual void setState_Psat(doublereal p, doublereal x)
Set the state to a saturated system at a particular pressure.
Definition: ThermoPhase.h:1552
std::vector< const XML_Node * > m_speciesData
Vector of pointers to the species databases.
Definition: ThermoPhase.h:1909
doublereal intEnergy_mass() const
Specific internal energy. Units: J/kg.
Definition: ThermoPhase.h:753
virtual void setState_RPX(doublereal rho, doublereal p, const doublereal *x)
Set the density (kg/m**3), pressure (Pa) and mole fractions.
virtual doublereal enthalpy_mole() const
Molar enthalpy. Units: J/kmol.
Definition: ThermoPhase.h:239
MultiSpeciesThermo m_spthermo
Pointer to the calculation manager for species reference-state thermodynamic properties.
Definition: ThermoPhase.h:1894
doublereal enthalpy_mass() const
Specific enthalpy. Units: J/kg.
Definition: ThermoPhase.h:748
double mixtureFraction(const double *fuelComp, const double *oxComp, ThermoBasis basis=ThermoBasis::molar, const std::string &element="Bilger") const
Compute the mixture fraction = kg fuel / (kg oxidizer + kg fuel) for the current mixture given fuel a...
AnyMap m_input
Data supplied via setParameters.
Definition: ThermoPhase.h:1898
virtual void setParameters(int n, doublereal *const c)
Set the equation of state parameters.
virtual doublereal minTemp(size_t k=npos) const
Minimum temperature for which the thermodynamic data for the species or phase are valid.
Definition: ThermoPhase.h:165
virtual void reportCSV(std::ofstream &csvFile) const
returns a summary of the state of the phase to a comma separated file.
void setEquivalenceRatio(double phi, const double *fuelComp, const double *oxComp, ThermoBasis basis=ThermoBasis::molar)
Set the mixture composition according to the equivalence ratio.
void setState_TPQ(double T, double P, double Q)
Set the temperature, pressure, and vapor fraction (quality).
virtual void invalidateCache()
Invalidate any cached values which are normally updated only when a change in state is detected.
void setState_conditional_TP(doublereal t, doublereal p, bool set_p)
Helper function used by setState_HPorUV and setState_SPorSV.
virtual void setState_VH(double v, double h, double tol=1e-9)
Set the specific volume (m^3/kg) and the specific enthalpy (J/kg)
Definition: ThermoPhase.h:1029
doublereal electricPotential() const
Returns the electric potential of this phase (V).
Definition: ThermoPhase.h:326
virtual void setState_SV(double s, double v, double tol=1e-9)
Set the specific entropy (J/kg/K) and specific volume (m^3/kg).
const AnyMap & input() const
Access input data associated with the phase description.
virtual void getParameters(int &n, doublereal *const c) const
Get the equation of state parameters in a vector.
A representation of the units associated with a dimensional quantity.
Definition: Units.h:30
Class XML_Node is a tree-based representation of the contents of an XML file.
Definition: xml.h:103
bool hasChild(const std::string &ch) const
Tests whether the current node has a child node with a particular name.
Definition: xml.cpp:529
XML_Node & child(const size_t n) const
Return a changeable reference to the n'th child of the current node.
Definition: xml.cpp:547
CTML ("Cantera Markup Language") is the variant of XML that Cantera uses to store data.
void equilibrate(const std::string &XY, const std::string &solver="auto", double rtol=1e-9, int max_steps=50000, int max_iter=100, int estimate_equil=0, int log_level=0)
Equilibrate a ThermoPhase object.
void importPhase(XML_Node &phase, ThermoPhase *th)
Import a phase information into an empty ThermoPhase object.
Namespace for the Cantera kernel.
Definition: AnyMap.h:29
const size_t npos
index returned by functions to indicate "no position"
Definition: ct_defs.h:192
const double Faraday
Faraday constant [C/kmol].
Definition: ct_defs.h:128
XML_Node * get_XML_File(const std::string &file, int debug=0)
Return a pointer to the XML tree for a Cantera input file.
Definition: global.cpp:140
doublereal dot(InputIter x_begin, InputIter x_end, InputIter2 y_begin)
Function that calculates a templated inner product.
Definition: utilities.h:77
doublereal getFloat(const XML_Node &parent, const std::string &name, const std::string &type="")
Get a floating-point value from a child element.
Definition: ctml.cpp:166
XML_Node * findXMLPhase(XML_Node *root, const std::string &phaseId)
Search an XML_Node tree for a named phase XML_Node.
Definition: xml.cpp:1049
std::string getChildValue(const XML_Node &parent, const std::string &nameString)
This function reads a child node with the name, nameString, and returns its XML value as the return s...
Definition: ctml.cpp:133
void setupPhase(ThermoPhase &phase, const AnyMap &phaseNode, const AnyMap &rootNode=AnyMap())
Initialize a ThermoPhase object.
const int cAC_CONVENTION_MOLAR
Definition: ThermoPhase.h:27
const double OneAtm
One atmosphere [Pa].
Definition: ct_defs.h:81
void warn_deprecated(const std::string &source, const AnyBase &node, const std::string &message)
A deprecation warning for syntax in an input file.
Definition: AnyMap.cpp:1901
void debuglog(const std::string &msg, int loglevel)
Write a message to the log only if loglevel > 0.
Definition: global.h:146
const double SmallNumber
smallest number to compare to zero.
Definition: ct_defs.h:153
std::vector< double > vector_fp
Turn on the use of stl vectors for the basic array type within cantera Vector of doubles.
Definition: ct_defs.h:184
T clip(const T &value, const T &lower, const T &upper)
Clip value such that lower <= value <= upper.
Definition: global.h:356
const int cSS_CONVENTION_TEMPERATURE
Definition: ThermoPhase.h:37
ThermoBasis
Differentiate between mole fractions and mass fractions for input mixture composition.
Definition: ThermoPhase.h:46
std::map< std::string, double > compositionMap
Map connecting a string name with a double.
Definition: ct_defs.h:176
compositionMap parseCompString(const std::string &ss, const std::vector< std::string > &names=std::vector< std::string >())
Parse a composition string into a map consisting of individual key:composition pairs.
Definition: stringUtils.cpp:59
Contains declarations for string manipulation functions within Cantera.