Cantera  4.0.0a1
Loading...
Searching...
No Matches
MultiPhase.cpp
Go to the documentation of this file.
1/**
2 * @file MultiPhase.cpp
3 * Definitions for the @link Cantera::MultiPhase MultiPhase@endlink
4 * object that is used to set up multiphase equilibrium problems (see @ref equilGroup).
5 */
6
7// This file is part of Cantera. See License.txt in the top-level directory or
8// at https://cantera.org/license.txt for license and copyright information.
9
17
18using namespace std;
19
20namespace Cantera
21{
22
23MultiPhase::~MultiPhase()
24{
25 for (size_t i = 0; i < m_phase.size(); i++) {
26 m_phase[i]->removeSpeciesLock();
27 }
28}
29
30void MultiPhase::addPhase(shared_ptr<ThermoPhase> p, double moles)
31{
32 if (m_init) {
33 throw CanteraError("MultiPhase::addPhase",
34 "phases cannot be added after init() has been called.");
35 }
36
37 if (!p->compatibleWithMultiPhase()) {
38 throw CanteraError("MultiPhase::addPhase", "Phase '{}'' is not "
39 "compatible with MultiPhase equilibrium solver", p->name());
40 }
41
42 p->addSpeciesLock(); // lock species list
43 m_phase.push_back(p); // save the pointer to the phase object
44
45 // store its number of moles
46 m_moles.push_back(moles);
47 m_temp_OK.push_back(true);
48
49 // update the total number of species
50 m_nsp += p->nSpecies();
51
52 // determine if this phase has new elements for each new element, add an
53 // entry in the map from names to index number + 1:
54
55 // iterate over the elements in this phase
56 for (size_t m = 0; m < p->nElements(); m++) {
57 string ename = p->elementName(m);
58
59 // if no entry is found for this element name, then it is a new element.
60 // In this case, add the name to the list of names, increment the
61 // element count, and add an entry to the name->(index+1) map.
62 if (m_enamemap.find(ename) == m_enamemap.end()) {
63 m_enamemap[ename] = m_nel + 1;
64 m_enames.push_back(ename);
65 m_atomicNumber.push_back(p->atomicNumber(m));
66
67 // Element 'E' (or 'e') is special. Note its location.
68 if (ename == "E" || ename == "e") {
69 m_eloc = m_nel;
70 }
71
72 m_nel++;
73 }
74 }
75
76 // If the mixture temperature hasn't been set, then set the temperature and
77 // pressure to the values for the phase being added. There is no good way to
78 // do this. However, this will be overridden later.
79 if (m_temp == 298.15 && p->temperature() > 2.0E-3) {
80 m_temp = p->temperature();
81 m_press = p->pressure();
82 }
83
84 // If this is a solution phase, update the minimum and maximum mixture
85 // temperatures. Stoichiometric phases are excluded, since a mixture may
86 // define multiple stoichiometric phases, each of which has thermo data
87 // valid only over a limited range. For example, a mixture might be defined
88 // to contain a phase representing water ice and one representing liquid
89 // water, only one of which should be present if the mixture represents an
90 // equilibrium state.
91 if (p->nSpecies() > 1) {
92 m_Tmin = std::max(p->minTemp(), m_Tmin);
93 m_Tmax = std::min(p->maxTemp(), m_Tmax);
94 }
95}
96
98{
99 if (m_init) {
100 return;
101 }
102
103 // allocate space for the atomic composition matrix
104 m_atoms.resize(m_nel, m_nsp, 0.0);
105 m_moleFractions.resize(m_nsp, 0.0);
106 m_elemAbundances.resize(m_nel, 0.0);
107
108 // iterate over the elements
109 // -> fill in m_atoms(m,k), m_snames(k), m_spphase(k), m_spstart(ip)
110 for (size_t m = 0; m < m_nel; m++) {
111 size_t k = 0;
112 // iterate over the phases
113 for (size_t ip = 0; ip < nPhases(); ip++) {
114 auto& p = m_phase[ip];
115 size_t nsp = p->nSpecies();
116 size_t mlocal = p->elementIndex(m_enames[m], false);
117 for (size_t kp = 0; kp < nsp; kp++) {
118 if (mlocal != npos) {
119 m_atoms(m, k) = p->nAtoms(kp, mlocal);
120 }
121 if (m == 0) {
122 m_snames.push_back(p->speciesName(kp));
123 if (kp == 0) {
124 m_spstart.push_back(m_spphase.size());
125 }
126 m_spphase.push_back(ip);
127 }
128 k++;
129 }
130 }
131 }
132
133 // set the initial composition within each phase to the
134 // mole fractions stored in the phase objects
135 m_init = true;
137 updatePhases();
138}
139
141{
142 if (!m_init) {
143 init();
144 }
145 m_phase[n]->setTemperature(m_temp);
146 m_phase[n]->setMoleFractions_NoNorm(
147 span<const double>(&m_moleFractions[m_spstart[n]], m_phase[n]->nSpecies()));
148 m_phase[n]->setPressure(m_press);
149 return *m_phase[n];
150}
151
152double MultiPhase::speciesMoles(size_t k) const
153{
154 size_t ip = m_spphase[k];
155 return m_moles[ip]*m_moleFractions[k];
156}
157
158double MultiPhase::elementMoles(size_t m) const
159{
160 double sum = 0.0;
161 for (size_t i = 0; i < nPhases(); i++) {
162 double phasesum = 0.0;
163 size_t nsp = m_phase[i]->nSpecies();
164 for (size_t ik = 0; ik < nsp; ik++) {
165 size_t k = speciesIndex(ik, i);
166 phasesum += m_atoms(m,k)*m_moleFractions[k];
167 }
168 sum += phasesum * m_moles[i];
169 }
170 return sum;
171}
172
173double MultiPhase::charge() const
174{
175 double sum = 0.0;
176 for (size_t i = 0; i < nPhases(); i++) {
177 sum += phaseCharge(i);
178 }
179 return sum;
180}
181
182size_t MultiPhase::speciesIndex(const string& speciesName, const string& phaseName)
183{
184 if (!m_init) {
185 init();
186 }
187 size_t p = phaseIndex(phaseName, true);
188 size_t k = m_phase[p]->speciesIndex(speciesName, true);
189 return m_spstart[p] + k;
190}
191
192double MultiPhase::phaseCharge(size_t p) const
193{
194 double phasesum = 0.0;
195 size_t nsp = m_phase[p]->nSpecies();
196 for (size_t ik = 0; ik < nsp; ik++) {
197 size_t k = speciesIndex(ik, p);
198 phasesum += m_phase[p]->charge(ik)*m_moleFractions[k];
199 }
200 return Faraday*phasesum*m_moles[p];
201}
202
203void MultiPhase::getChemPotentials(span<double> mu) const
204{
205 updatePhases();
206 size_t loc = 0;
207 for (size_t i = 0; i < nPhases(); i++) {
208 size_t nsp = m_phase[i]->nSpecies();
209 m_phase[i]->getChemPotentials(mu.subspan(loc, nsp));
210 loc += nsp;
211 }
212}
213
214void MultiPhase::getValidChemPotentials(double not_mu, span<double> mu,
215 bool standard) const
216{
217 updatePhases();
218 // iterate over the phases
219 size_t loc = 0;
220 for (size_t i = 0; i < nPhases(); i++) {
221 if (tempOK(i) || m_phase[i]->nSpecies() > 1) {
222 if (!standard) {
223 m_phase[i]->getChemPotentials(mu.subspan(loc, m_phase[i]->nSpecies()));
224 } else {
225 m_phase[i]->getStandardChemPotentials(
226 mu.subspan(loc, m_phase[i]->nSpecies()));
227 }
228 } else {
229 fill(mu.begin() + loc, mu.begin() + loc + m_phase[i]->nSpecies(), not_mu);
230 }
231 loc += m_phase[i]->nSpecies();
232 }
233}
234
235bool MultiPhase::solutionSpecies(size_t k) const
236{
237 if (m_phase[m_spphase[k]]->nSpecies() > 1) {
238 return true;
239 } else {
240 return false;
241 }
242}
243
244double MultiPhase::gibbs() const
245{
246 double sum = 0.0;
247 updatePhases();
248 for (size_t i = 0; i < nPhases(); i++) {
249 if (m_moles[i] > 0.0) {
250 sum += m_phase[i]->gibbs_mole() * m_moles[i];
251 }
252 }
253 return sum;
254}
255
257{
258 double sum = 0.0;
259 updatePhases();
260 for (size_t i = 0; i < nPhases(); i++) {
261 if (m_moles[i] > 0.0) {
262 sum += m_phase[i]->enthalpy_mole() * m_moles[i];
263 }
264 }
265 return sum;
266}
267
269{
270 double sum = 0.0;
271 updatePhases();
272 for (size_t i = 0; i < nPhases(); i++) {
273 if (m_moles[i] > 0.0) {
274 sum += m_phase[i]->intEnergy_mole() * m_moles[i];
275 }
276 }
277 return sum;
278}
279
281{
282 double sum = 0.0;
283 updatePhases();
284 for (size_t i = 0; i < nPhases(); i++) {
285 if (m_moles[i] > 0.0) {
286 sum += m_phase[i]->entropy_mole() * m_moles[i];
287 }
288 }
289 return sum;
290}
291
292double MultiPhase::cp() const
293{
294 double sum = 0.0;
295 updatePhases();
296 for (size_t i = 0; i < nPhases(); i++) {
297 if (m_moles[i] > 0.0) {
298 sum += m_phase[i]->cp_mole() * m_moles[i];
299 }
300 }
301 return sum;
302}
303
304void MultiPhase::setPhaseMoleFractions(const size_t n, span<const double> x)
305{
306 if (!m_init) {
307 init();
308 }
309 auto& p = m_phase[n];
310 p->setState_TPX(m_temp, m_press, x.subspan(0, p->nSpecies()));
311 size_t istart = m_spstart[n];
312 for (size_t k = 0; k < p->nSpecies(); k++) {
313 m_moleFractions[istart+k] = x[k];
314 }
315}
316
318{
319 size_t kk = nSpecies();
320 vector<double> moles(kk, 0.0);
321 for (size_t k = 0; k < kk; k++) {
322 moles[k] = std::max(getValue(xMap, speciesName(k), 0.0), 0.0);
323 }
324 setMoles(moles);
325}
326
327void MultiPhase::setMolesByName(const string& x)
328{
329 // build the composition map from the string, and then set the moles.
331 setMolesByName(xx);
332}
333
334void MultiPhase::getMoles(span<double> molNum) const
335{
336 // First copy in the mole fractions
337 copy(m_moleFractions.begin(), m_moleFractions.end(), molNum.begin());
338 double* dtmp = molNum.data();
339 for (size_t ip = 0; ip < nPhases(); ip++) {
340 double phasemoles = m_moles[ip];
341 size_t nsp = m_phase[ip]->nSpecies();
342 for (size_t ik = 0; ik < nsp; ik++) {
343 *(dtmp++) *= phasemoles;
344 }
345 }
346}
347
348void MultiPhase::setMoles(span<const double> n)
349{
350 checkArraySize("MultiPhase::setMoles", n.size(), nSpecies());
351 if (!m_init) {
352 init();
353 }
354 size_t loc = 0;
355 size_t k = 0;
356 for (size_t ip = 0; ip < nPhases(); ip++) {
357 auto& p = m_phase[ip];
358 size_t nsp = p->nSpecies();
359 double phasemoles = 0.0;
360 for (size_t ik = 0; ik < nsp; ik++) {
361 phasemoles += n[k];
362 k++;
363 }
364 m_moles[ip] = phasemoles;
365 if (nsp > 1) {
366 if (phasemoles > 0.0) {
367 p->setState_TPX(m_temp, m_press, n.subspan(loc, nsp));
368 p->getMoleFractions(span<double>(&m_moleFractions[loc], nsp));
369 } else {
370 p->getMoleFractions(span<double>(&m_moleFractions[loc], nsp));
371 }
372 } else {
373 m_moleFractions[loc] = 1.0;
374 }
375 loc += nsp;
376 }
377}
378
379void MultiPhase::getElemAbundances(span<double> elemAbundances) const
380{
382 for (size_t eGlobal = 0; eGlobal < m_nel; eGlobal++) {
383 elemAbundances[eGlobal] = m_elemAbundances[eGlobal];
384 }
385}
386
388{
389 size_t loc = 0;
390 double spMoles;
391 for (size_t eGlobal = 0; eGlobal < m_nel; eGlobal++) {
392 m_elemAbundances[eGlobal] = 0.0;
393 }
394 for (size_t ip = 0; ip < nPhases(); ip++) {
395 size_t nspPhase = m_phase[ip]->nSpecies();
396 double phasemoles = m_moles[ip];
397 for (size_t ik = 0; ik < nspPhase; ik++) {
398 size_t kGlobal = loc + ik;
399 spMoles = m_moleFractions[kGlobal] * phasemoles;
400 for (size_t eGlobal = 0; eGlobal < m_nel; eGlobal++) {
401 m_elemAbundances[eGlobal] += m_atoms(eGlobal, kGlobal) * spMoles;
402 }
403 }
404 loc += nspPhase;
405 }
406}
407
408double MultiPhase::volume() const
409{
410 double sum = 0;
411 for (size_t i = 0; i < nPhases(); i++) {
412 double vol = 1.0/m_phase[i]->molarDensity();
413 sum += m_moles[i] * vol;
414 }
415 return sum;
416}
417
418namespace {
419
420struct EquilPhaseGuard
421{
422 explicit EquilPhaseGuard(MultiPhase& mix) : m_mix(mix)
423 {
424 for (size_t ip = 0; ip < m_mix.nPhases(); ++ip) {
425 m_mix.phase(ip).beginEquilibrate();
426 }
427 }
428
429 ~EquilPhaseGuard()
430 {
431 for (size_t ip = 0; ip < m_mix.nPhases(); ++ip) {
432 m_mix.phase(ip).endEquilibrate();
433 }
434 }
435
436private:
437 MultiPhase& m_mix;
438};
439
440} // namespace
441
442double MultiPhase::equilibrate_MultiPhaseEquil(int XY, double err, int maxsteps,
443 int maxiter, int loglevel)
444{
445 bool strt = false;
446 double dta = 0.0;
447 if (!m_init) {
448 init();
449 }
450
451 if (XY == TP) {
452 // create an equilibrium manager
453 MultiPhaseEquil e(this);
454 return e.equilibrate(XY, err, maxsteps, loglevel);
455 } else if (XY == HP) {
456 double h0 = enthalpy();
457 double Tlow = 0.5*m_Tmin; // lower bound on T
458 double Thigh = 2.0*m_Tmax; // upper bound on T
459 double Hlow = Undef, Hhigh = Undef;
460 for (int n = 0; n < maxiter; n++) {
461 // if 'strt' is false, the current composition will be used as
462 // the starting estimate; otherwise it will be estimated
463 MultiPhaseEquil e(this, strt);
464 // start with a loose error tolerance, but tighten it as we get
465 // close to the final temperature
466
467 try {
468 e.equilibrate(TP, err, maxsteps, loglevel);
469 double hnow = enthalpy();
470 // the equilibrium enthalpy monotonically increases with T;
471 // if the current value is below the target, the we know the
472 // current temperature is too low. Set
473 if (hnow < h0) {
474 if (m_temp > Tlow) {
475 Tlow = m_temp;
476 Hlow = hnow;
477 }
478 } else {
479 // the current enthalpy is greater than the target;
480 // therefore the current temperature is too high.
481 if (m_temp < Thigh) {
482 Thigh = m_temp;
483 Hhigh = hnow;
484 }
485 }
486 double dt;
487 if (Hlow != Undef && Hhigh != Undef) {
488 double cpb = (Hhigh - Hlow)/(Thigh - Tlow);
489 dt = (h0 - hnow)/cpb;
490 dta = fabs(dt);
491 double dtmax = 0.5*fabs(Thigh - Tlow);
492 if (dta > dtmax) {
493 dt *= dtmax/dta;
494 }
495 } else {
496 double tnew = sqrt(Tlow*Thigh);
497 dt = tnew - m_temp;
498 }
499
500 double herr = fabs((h0 - hnow)/h0);
501
502 if (herr < err) {
503 return err;
504 }
505 double tnew = m_temp + dt;
506 if (tnew < 0.0) {
507 tnew = 0.5*m_temp;
508 }
509 setTemperature(tnew);
510
511 // if the size of Delta T is not too large, use
512 // the current composition as the starting estimate
513 if (dta < 100.0) {
514 strt = false;
515 }
516
517 } catch (CanteraError&) {
518 if (!strt) {
519 strt = true;
520 } else {
521 double tnew = 0.5*(m_temp + Thigh);
522 if (fabs(tnew - m_temp) < 1.0) {
523 tnew = m_temp + 1.0;
524 }
525 setTemperature(tnew);
526 }
527 }
528 }
529 throw CanteraError("MultiPhase::equilibrate_MultiPhaseEquil",
530 "No convergence for T");
531 } else if (XY == SP) {
532 double s0 = entropy();
533 double Tlow = 1.0; // lower bound on T
534 double Thigh = 1.0e6; // upper bound on T
535 for (int n = 0; n < maxiter; n++) {
536 MultiPhaseEquil e(this, strt);
537
538 try {
539 e.equilibrate(TP, err, maxsteps, loglevel);
540 double snow = entropy();
541 if (snow < s0) {
542 Tlow = std::max(Tlow, m_temp);
543 } else {
544 Thigh = std::min(Thigh, m_temp);
545 }
546 double dt = (s0 - snow)*m_temp/cp();
547 double dtmax = 0.5*fabs(Thigh - Tlow);
548 dtmax = (dtmax > 500.0 ? 500.0 : dtmax);
549 dta = fabs(dt);
550 if (dta > dtmax) {
551 dt *= dtmax/dta;
552 }
553 if (dta < 1.0e-4) {
554 return err;
555 }
556 double tnew = m_temp + dt;
557 setTemperature(tnew);
558
559 // if the size of Delta T is not too large, use
560 // the current composition as the starting estimate
561 if (dta < 100.0) {
562 strt = false;
563 }
564 } catch (CanteraError&) {
565 if (!strt) {
566 strt = true;
567 } else {
568 double tnew = 0.5*(m_temp + Thigh);
569 setTemperature(tnew);
570 }
571 }
572 }
573 throw CanteraError("MultiPhase::equilibrate_MultiPhaseEquil",
574 "No convergence for T");
575 } else if (XY == TV) {
576 double v0 = volume();
577 bool start = true;
578 for (int n = 0; n < maxiter; n++) {
579 double pnow = pressure();
580 MultiPhaseEquil e(this, start);
581 start = false;
582
583 e.equilibrate(TP, err, maxsteps, loglevel);
584 double vnow = volume();
585 double verr = fabs((v0 - vnow)/v0);
586
587 if (verr < err) {
588 return err;
589 }
590 // find dV/dP
591 setPressure(pnow*1.01);
592 double dVdP = (volume() - vnow)/(0.01*pnow);
593 setPressure(pnow + 0.5*(v0 - vnow)/dVdP);
594 }
595 } else {
596 throw CanteraError("MultiPhase::equilibrate_MultiPhaseEquil",
597 "unknown option");
598 }
599 return -1.0;
600}
601
602void MultiPhase::equilibrate(const string& XY, const string& solver,
603 double rtol, int max_steps, int max_iter,
604 int estimate_equil, int log_level)
605{
606 // Save the initial state so that it can be restored in case one of the
607 // solvers fails
608 vector<double> initial_moleFractions = m_moleFractions;
609 vector<double> initial_moles = m_moles;
610 double initial_T = m_temp;
611 double initial_P = m_press;
612 int ixy = _equilflag(XY.c_str());
613 EquilPhaseGuard phase_guard(*this);
614 if (solver == "auto" || solver == "vcs") {
615 try {
616 debuglog("Trying VCS equilibrium solver\n", log_level);
617 vcs_MultiPhaseEquil eqsolve(this, log_level-1);
618 int ret = eqsolve.equilibrate(ixy, estimate_equil, log_level-1,
619 rtol, max_steps);
620 if (ret) {
621 throw CanteraError("MultiPhase::equilibrate",
622 "VCS solver failed. Return code: {}", ret);
623 }
624 debuglog("VCS solver succeeded\n", log_level);
625 return;
626 } catch (std::exception& err) {
627 debuglog("VCS solver failed.\n", log_level);
628 debuglog(err.what(), log_level);
629 m_moleFractions = initial_moleFractions;
630 m_moles = initial_moles;
631 m_temp = initial_T;
632 m_press = initial_P;
633 updatePhases();
634 if (solver == "auto") {
635 } else {
636 throw;
637 }
638 }
639 }
640
641 if (solver == "auto" || solver == "gibbs") {
642 try {
643 debuglog("Trying MultiPhaseEquil (Gibbs) equilibrium solver\n",
644 log_level);
645 equilibrate_MultiPhaseEquil(ixy, rtol, max_steps, max_iter,
646 log_level-1);
647 debuglog("MultiPhaseEquil solver succeeded\n", log_level);
648 return;
649 } catch (std::exception& err) {
650 debuglog("MultiPhaseEquil solver failed.\n", log_level);
651 debuglog(err.what(), log_level);
652 m_moleFractions = initial_moleFractions;
653 m_moles = initial_moles;
654 m_temp = initial_T;
655 m_press = initial_P;
656 updatePhases();
657 throw;
658 }
659 }
660
661 if (solver != "auto") {
662 throw CanteraError("MultiPhase::equilibrate",
663 "Invalid solver specified: '" + solver + "'");
664 }
665}
666
667void MultiPhase::setTemperature(const double T)
668{
669 if (!m_init) {
670 init();
671 }
672 m_temp = T;
673 updatePhases();
674}
675
676size_t MultiPhase::checkElementIndex(size_t m) const
677{
678 if (m < m_nel) {
679 return m;
680 }
681 throw IndexError("MultiPhase::checkElementIndex", "elements", m, m_nel);
682}
683
684string MultiPhase::elementName(size_t m) const
685{
686 if (m < m_nel) {
687 return m_enames[m];
688 }
689 throw IndexError("MultiPhase::elementName", "element", m, m_nel);
690}
691
692size_t MultiPhase::elementIndex(const string& name, bool raise) const
693{
694 for (size_t e = 0; e < m_nel; e++) {
695 if (m_enames[e] == name) {
696 return e;
697 }
698 }
699 if (!raise) {
700 return npos;
701 }
702 throw CanteraError("MultiPhase::elementIndex", "Element '{}' not found", name);
703}
704
705string MultiPhase::speciesName(size_t k) const
706{
707 if (k < m_nsp) {
708 return m_snames[k];
709 }
710 throw IndexError("MultiPhase::speciesName", "species", k, m_nsp);
711}
712
713double MultiPhase::nAtoms(const size_t kGlob, const size_t mGlob) const
714{
715 return m_atoms(mGlob, kGlob);
716}
717
718void MultiPhase::getMoleFractions(span<double> x) const
719{
720 checkArraySize("MultiPhase::getMoleFractions", x.size(), nSpecies());
721 std::copy(m_moleFractions.begin(), m_moleFractions.end(), x.begin());
722}
723
724string MultiPhase::phaseName(size_t iph) const
725{
726 if (iph < m_phase.size()) {
727 return m_phase[iph]->name();
728 }
729 throw IndexError("MultiPhase::phaseName", "phase", iph, m_phase.size());
730}
731
732size_t MultiPhase::phaseIndex(const string& pName, bool raise) const
733{
734 for (int iph = 0; iph < (int) nPhases(); iph++) {
735 if (m_phase[iph]->name() == pName) {
736 return iph;
737 }
738 }
739 if (!raise) {
740 return npos;
741 }
742 throw CanteraError("MultiPhase::phaseIndex", "Phase '{}' not found", pName);
743}
744
745double MultiPhase::phaseMoles(const size_t n) const
746{
747 return m_moles[n];
748}
749
750void MultiPhase::setPhaseMoles(const size_t n, const double moles)
751{
752 m_moles[n] = moles;
753}
754
755size_t MultiPhase::speciesPhaseIndex(const size_t kGlob) const
756{
757 return m_spphase[kGlob];
758}
759
760double MultiPhase::moleFraction(const size_t kGlob) const
761{
762 return m_moleFractions[kGlob];
763}
764
765bool MultiPhase::tempOK(const size_t p) const
766{
767 return m_temp_OK[p];
768}
769
771{
772 size_t loc = 0;
773 for (size_t ip = 0; ip < nPhases(); ip++) {
774 auto& p = m_phase[ip];
775 p->getMoleFractions(span<double>(m_moleFractions.data() + loc, p->nSpecies()));
776 loc += p->nSpecies();
777 }
779}
780
782{
783 size_t loc = 0;
784 for (size_t p = 0; p < nPhases(); p++) {
785 size_t nsp = m_phase[p]->nSpecies();
786 span<const double> X(m_moleFractions.data() + loc, nsp);
787 m_phase[p]->setState_TPX(m_temp, m_press, X);
788 loc += nsp;
789 m_temp_OK[p] = true;
790 if (m_temp < m_phase[p]->minTemp() || m_temp > m_phase[p]->maxTemp()) {
791 m_temp_OK[p] = false;
792 }
793 }
794}
795
796std::ostream& operator<<(std::ostream& s, MultiPhase& x)
797{
798 x.updatePhases();
799 for (size_t ip = 0; ip < x.nPhases(); ip++) {
800 if (x.phase(ip).name() != "") {
801 s << "*************** " << x.phase(ip).name() << " *****************" << std::endl;
802 } else {
803 s << "*************** Phase " << ip << " *****************" << std::endl;
804 }
805 s << "Moles: " << x.phaseMoles(ip) << std::endl;
806
807 s << x.phase(ip).report() << std::endl;
808 }
809 return s;
810}
811
812}
Chemical equilibrium.
Headers for the MultiPhase object that is used to set up multiphase equilibrium problems (see Chemica...
Header file for class ThermoPhase, the base class for phases with thermodynamic properties,...
Base class for exceptions thrown by Cantera classes.
void resize(size_t n, size_t m, double v=0.0) override
Resize the matrix.
An array index is out of range.
Multiphase chemical equilibrium solver.
A class for multiphase mixtures.
Definition MultiPhase.h:62
void getMoleFractions(span< double > x) const
Returns the global Species mole fractions.
void init()
Process phases and build atomic composition array.
size_t speciesIndex(size_t k, size_t p) const
Return the global index of the species belonging to phase number p with local index k within the phas...
Definition MultiPhase.h:206
bool solutionSpecies(size_t kGlob) const
Return true is species kGlob is a species in a multicomponent solution phase.
void getMoles(span< double > molNum) const
Get the mole numbers of all species in the multiphase object.
double nAtoms(const size_t kGlob, const size_t mGlob) const
Returns the Number of atoms of global element mGlob in global species kGlob.
void setMolesByName(const Composition &xMap)
Set the number of moles of species in the mixture.
DenseMatrix m_atoms
Global Stoichiometric Coefficient array.
Definition MultiPhase.h:536
double gibbs() const
The Gibbs function of the mixture [J].
void setMoles(span< const double > n)
Sets all of the global species mole numbers.
size_t m_nel
Number of distinct elements in all of the phases.
Definition MultiPhase.h:581
double speciesMoles(size_t kGlob) const
Returns the moles of global species k. units = kmol.
double m_temp
Current value of the temperature (kelvin)
Definition MultiPhase.h:575
void calcElemAbundances() const
Calculate the element abundance vector.
size_t nSpecies() const
Number of species, summed over all phases.
Definition MultiPhase.h:116
size_t checkElementIndex(size_t m) const
Check that the specified element index is in range.
double enthalpy() const
The enthalpy of the mixture [J].
double pressure() const
Pressure [Pa].
Definition MultiPhase.h:352
vector< size_t > m_spstart
Vector of ints containing of first species index in the global list of species for each phase.
Definition MultiPhase.h:555
vector< size_t > m_spphase
Mapping between the global species number and the phase ID.
Definition MultiPhase.h:547
double minTemp() const
Minimum temperature for which all solution phases have valid thermo data.
Definition MultiPhase.h:226
vector< double > m_moleFractions
Locally stored vector of mole fractions of all species comprising the MultiPhase object.
Definition MultiPhase.h:540
size_t phaseIndex(const string &pName, bool raise=true) const
Returns the index, given the phase name.
void getElemAbundances(span< double > elemAbundances) const
Retrieves a vector of element abundances.
vector< double > m_elemAbundances
Vector of element abundances.
Definition MultiPhase.h:613
void setPhaseMoleFractions(const size_t n, span< const double > x)
Set the Mole fractions of the nth phase.
double equilibrate_MultiPhaseEquil(int XY, double err, int maxsteps, int maxiter, int loglevel)
Set the mixture to a state of chemical equilibrium using the MultiPhaseEquil solver.
vector< bool > m_temp_OK
Vector of bools indicating whether temperatures are ok for phases.
Definition MultiPhase.h:598
double phaseCharge(size_t p) const
Charge (Coulombs) of phase with index p.
size_t nPhases() const
Number of phases.
Definition MultiPhase.h:389
size_t m_eloc
Global ID of the element corresponding to the electronic charge.
Definition MultiPhase.h:591
double entropy() const
The entropy of the mixture [J/K].
double moleFraction(const size_t kGlob) const
Returns the mole fraction of global species k.
void getChemPotentials(span< double > mu) const
Returns a vector of Chemical potentials.
string speciesName(size_t kGlob) const
Name of species with global index kGlob.
vector< shared_ptr< ThermoPhase > > m_phase
Vector of phase objects.
Definition MultiPhase.h:528
double m_press
Current value of the pressure (Pa)
Definition MultiPhase.h:578
bool tempOK(size_t p) const
Return true if the phase p has valid thermo data for the current temperature.
map< string, size_t > m_enamemap
Returns the global element index, given the element string name.
Definition MultiPhase.h:572
size_t speciesPhaseIndex(const size_t kGlob) const
Returns the phase index of the Kth "global" species.
void getValidChemPotentials(double not_mu, span< double > mu, bool standard=false) const
Returns a vector of Valid chemical potentials.
void setPressure(double P)
Set the pressure [Pa].
Definition MultiPhase.h:367
vector< string > m_enames
String names of the global elements.
Definition MultiPhase.h:559
void addPhase(shared_ptr< ThermoPhase > p, double moles)
Add a phase to the mixture.
double phaseMoles(const size_t n) const
Return the number of moles in phase n.
size_t m_nsp
Number of distinct species in all of the phases.
Definition MultiPhase.h:584
vector< int > m_atomicNumber
Atomic number of each global element.
Definition MultiPhase.h:562
double volume() const
The total mixture volume [m^3].
void uploadMoleFractionsFromPhases()
Update the locally-stored composition within this object to match the current compositions of the pha...
bool m_init
True if the init() routine has been called, and the MultiPhase frozen.
Definition MultiPhase.h:587
vector< string > m_snames
Vector of species names in the problem.
Definition MultiPhase.h:566
double m_Tmin
Minimum temperature for which thermo parameterizations are valid.
Definition MultiPhase.h:602
void updatePhases() const
Set the states of the phase objects to the locally-stored state within this MultiPhase object.
double charge() const
Total charge summed over all phases (Coulombs).
double cp() const
Heat capacity at constant pressure [J/K].
size_t elementIndex(const string &name, bool raise=true) const
Returns the index of the element with name name.
void setTemperature(const double T)
Set the temperature [K].
ThermoPhase & phase(size_t n)
Return a reference to phase n.
double maxTemp() const
Maximum temperature for which all solution phases have valid thermo data.
Definition MultiPhase.h:233
double IntEnergy() const
The internal energy of the mixture [J].
string elementName(size_t m) const
Returns the name of the global element m.
vector< double > m_moles
Vector of the number of moles in each phase.
Definition MultiPhase.h:525
void setPhaseMoles(const size_t n, const double moles)
Set the number of moles of phase with index n.
double elementMoles(size_t m) const
Total moles of global element m, summed over all phases.
string phaseName(size_t iph) const
Returns the name of the n'th phase.
double m_Tmax
Minimum temperature for which thermo parameterizations are valid.
Definition MultiPhase.h:606
string name() const
Return the name of the phase.
Definition Phase.cpp:20
Base class for a phase with thermodynamic properties.
virtual string report(bool show_thermo=true, double threshold=-1e-14) const
returns a summary of the state of the phase as a string
Cantera's Interface to the Multiphase chemical equilibrium solver.
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.
Composition parseCompString(const string &ss, const vector< string > &names)
Parse a composition string into a map consisting of individual key:composition pairs.
void equilibrate(const string &XY, const 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 MultiPhase object.
void debuglog(const string &msg, int loglevel)
Write a message to the log only if loglevel > 0.
Definition global.h:154
const double Faraday
Faraday constant [C/kmol].
Definition ct_defs.h:134
Namespace for the Cantera kernel.
Definition AnyMap.cpp:595
const size_t npos
index returned by functions to indicate "no position"
Definition ct_defs.h:183
const double Undef
Fairly random number to be used to initialize variables against to see if they are subsequently defin...
Definition ct_defs.h:167
int _equilflag(const char *xy)
map property strings to integers
Definition ChemEquil.cpp:20
std::ostream & operator<<(std::ostream &s, const Array2D &m)
Output the current contents of the Array2D object.
Definition Array.cpp:101
const U & getValue(const map< T, U > &m, const T &key, const U &default_val)
Const accessor for a value in a map.
Definition utilities.h:223
map< string, double > Composition
Map from string names to doubles.
Definition ct_defs.h:180
void checkArraySize(const char *procedure, size_t available, size_t required)
Wrapper for throwing ArraySizeError.
Contains declarations for string manipulation functions within Cantera.
Various templated functions that carry out common vector and polynomial operations (see Templated Arr...
Interface class for the vcsnonlinear solver.