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