Cantera  3.2.0a5
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
186{
187 warn_deprecated("MultiPhase::checkPhaseArraySize",
188 "To be removed after Cantera 3.2. Unused.");
189 if (nPhases() > mm) {
190 throw ArraySizeError("MultiPhase::checkPhaseIndex", mm, nPhases());
191 }
192}
193
194double MultiPhase::speciesMoles(size_t k) const
195{
196 size_t ip = m_spphase[k];
197 return m_moles[ip]*m_moleFractions[k];
198}
199
200double MultiPhase::elementMoles(size_t m) const
201{
202 double sum = 0.0;
203 for (size_t i = 0; i < nPhases(); i++) {
204 double phasesum = 0.0;
205 size_t nsp = m_phase[i]->nSpecies();
206 for (size_t ik = 0; ik < nsp; ik++) {
207 size_t k = speciesIndex(ik, i);
208 phasesum += m_atoms(m,k)*m_moleFractions[k];
209 }
210 sum += phasesum * m_moles[i];
211 }
212 return sum;
213}
214
215double MultiPhase::charge() const
216{
217 double sum = 0.0;
218 for (size_t i = 0; i < nPhases(); i++) {
219 sum += phaseCharge(i);
220 }
221 return sum;
222}
223
224size_t MultiPhase::speciesIndex(const string& speciesName, const string& phaseName)
225{
226 if (!m_init) {
227 init();
228 }
229 size_t p = phaseIndex(phaseName, true);
230 size_t k = m_phase[p]->speciesIndex(speciesName, true);
231 return m_spstart[p] + k;
232}
233
234double MultiPhase::phaseCharge(size_t p) const
235{
236 double phasesum = 0.0;
237 size_t nsp = m_phase[p]->nSpecies();
238 for (size_t ik = 0; ik < nsp; ik++) {
239 size_t k = speciesIndex(ik, p);
240 phasesum += m_phase[p]->charge(ik)*m_moleFractions[k];
241 }
242 return Faraday*phasesum*m_moles[p];
243}
244
245void MultiPhase::getChemPotentials(double* mu) const
246{
247 updatePhases();
248 size_t loc = 0;
249 for (size_t i = 0; i < nPhases(); i++) {
250 m_phase[i]->getChemPotentials(mu + loc);
251 loc += m_phase[i]->nSpecies();
252 }
253}
254
255void MultiPhase::getValidChemPotentials(double not_mu, double* mu, bool standard) const
256{
257 updatePhases();
258 // iterate over the phases
259 size_t loc = 0;
260 for (size_t i = 0; i < nPhases(); i++) {
261 if (tempOK(i) || m_phase[i]->nSpecies() > 1) {
262 if (!standard) {
263 m_phase[i]->getChemPotentials(mu + loc);
264 } else {
265 m_phase[i]->getStandardChemPotentials(mu + loc);
266 }
267 } else {
268 fill(mu + loc, mu + loc + m_phase[i]->nSpecies(), not_mu);
269 }
270 loc += m_phase[i]->nSpecies();
271 }
272}
273
274bool MultiPhase::solutionSpecies(size_t k) const
275{
276 if (m_phase[m_spphase[k]]->nSpecies() > 1) {
277 return true;
278 } else {
279 return false;
280 }
281}
282
283double MultiPhase::gibbs() const
284{
285 double sum = 0.0;
286 updatePhases();
287 for (size_t i = 0; i < nPhases(); i++) {
288 if (m_moles[i] > 0.0) {
289 sum += m_phase[i]->gibbs_mole() * m_moles[i];
290 }
291 }
292 return sum;
293}
294
296{
297 double sum = 0.0;
298 updatePhases();
299 for (size_t i = 0; i < nPhases(); i++) {
300 if (m_moles[i] > 0.0) {
301 sum += m_phase[i]->enthalpy_mole() * m_moles[i];
302 }
303 }
304 return sum;
305}
306
308{
309 double sum = 0.0;
310 updatePhases();
311 for (size_t i = 0; i < nPhases(); i++) {
312 if (m_moles[i] > 0.0) {
313 sum += m_phase[i]->intEnergy_mole() * m_moles[i];
314 }
315 }
316 return sum;
317}
318
320{
321 double sum = 0.0;
322 updatePhases();
323 for (size_t i = 0; i < nPhases(); i++) {
324 if (m_moles[i] > 0.0) {
325 sum += m_phase[i]->entropy_mole() * m_moles[i];
326 }
327 }
328 return sum;
329}
330
331double MultiPhase::cp() const
332{
333 double sum = 0.0;
334 updatePhases();
335 for (size_t i = 0; i < nPhases(); i++) {
336 if (m_moles[i] > 0.0) {
337 sum += m_phase[i]->cp_mole() * m_moles[i];
338 }
339 }
340 return sum;
341}
342
343void MultiPhase::setPhaseMoleFractions(const size_t n, const double* const x)
344{
345 if (!m_init) {
346 init();
347 }
348 ThermoPhase* p = m_phase[n];
350 size_t istart = m_spstart[n];
351 for (size_t k = 0; k < p->nSpecies(); k++) {
352 m_moleFractions[istart+k] = x[k];
353 }
354}
355
357{
358 size_t kk = nSpecies();
359 vector<double> moles(kk, 0.0);
360 for (size_t k = 0; k < kk; k++) {
361 moles[k] = std::max(getValue(xMap, speciesName(k), 0.0), 0.0);
362 }
363 setMoles(moles.data());
364}
365
366void MultiPhase::setMolesByName(const string& x)
367{
368 // build the composition map from the string, and then set the moles.
370 setMolesByName(xx);
371}
372
373void MultiPhase::getMoles(double* molNum) const
374{
375 // First copy in the mole fractions
376 copy(m_moleFractions.begin(), m_moleFractions.end(), molNum);
377 double* dtmp = molNum;
378 for (size_t ip = 0; ip < nPhases(); ip++) {
379 double phasemoles = m_moles[ip];
380 ThermoPhase* p = m_phase[ip];
381 size_t nsp = p->nSpecies();
382 for (size_t ik = 0; ik < nsp; ik++) {
383 *(dtmp++) *= phasemoles;
384 }
385 }
386}
387
388void MultiPhase::setMoles(const double* n)
389{
390 if (!m_init) {
391 init();
392 }
393 size_t loc = 0;
394 size_t k = 0;
395 for (size_t ip = 0; ip < nPhases(); ip++) {
396 ThermoPhase* p = m_phase[ip];
397 size_t nsp = p->nSpecies();
398 double phasemoles = 0.0;
399 for (size_t ik = 0; ik < nsp; ik++) {
400 phasemoles += n[k];
401 k++;
402 }
403 m_moles[ip] = phasemoles;
404 if (nsp > 1) {
405 if (phasemoles > 0.0) {
406 p->setState_TPX(m_temp, m_press, n + loc);
408 } else {
410 }
411 } else {
412 m_moleFractions[loc] = 1.0;
413 }
414 loc += nsp;
415 }
416}
417
418void MultiPhase::addSpeciesMoles(const int indexS, const double addedMoles)
419{
420 vector<double> tmpMoles(m_nsp, 0.0);
421 getMoles(tmpMoles.data());
422 tmpMoles[indexS] += addedMoles;
423 tmpMoles[indexS] = std::max(tmpMoles[indexS], 0.0);
424 setMoles(tmpMoles.data());
425}
426
427void MultiPhase::setState_TP(const double T, const double Pres)
428{
429 if (!m_init) {
430 init();
431 }
432 m_temp = T;
433 m_press = Pres;
434 updatePhases();
435}
436
437void MultiPhase::setState_TPMoles(const double T, const double Pres, const double* n)
438{
439 m_temp = T;
440 m_press = Pres;
441 setMoles(n);
442}
443
444void MultiPhase::getElemAbundances(double* elemAbundances) const
445{
447 for (size_t eGlobal = 0; eGlobal < m_nel; eGlobal++) {
448 elemAbundances[eGlobal] = m_elemAbundances[eGlobal];
449 }
450}
451
453{
454 size_t loc = 0;
455 double spMoles;
456 for (size_t eGlobal = 0; eGlobal < m_nel; eGlobal++) {
457 m_elemAbundances[eGlobal] = 0.0;
458 }
459 for (size_t ip = 0; ip < nPhases(); ip++) {
460 ThermoPhase* p = m_phase[ip];
461 size_t nspPhase = p->nSpecies();
462 double phasemoles = m_moles[ip];
463 for (size_t ik = 0; ik < nspPhase; ik++) {
464 size_t kGlobal = loc + ik;
465 spMoles = m_moleFractions[kGlobal] * phasemoles;
466 for (size_t eGlobal = 0; eGlobal < m_nel; eGlobal++) {
467 m_elemAbundances[eGlobal] += m_atoms(eGlobal, kGlobal) * spMoles;
468 }
469 }
470 loc += nspPhase;
471 }
472}
473
474double MultiPhase::volume() const
475{
476 double sum = 0;
477 for (size_t i = 0; i < nPhases(); i++) {
478 double vol = 1.0/m_phase[i]->molarDensity();
479 sum += m_moles[i] * vol;
480 }
481 return sum;
482}
483
484double MultiPhase::equilibrate_MultiPhaseEquil(int XY, double err, int maxsteps,
485 int maxiter, int loglevel)
486{
487 bool strt = false;
488 double dta = 0.0;
489 if (!m_init) {
490 init();
491 }
492
493 if (XY == TP) {
494 // create an equilibrium manager
495 MultiPhaseEquil e(this);
496 return e.equilibrate(XY, err, maxsteps, loglevel);
497 } else if (XY == HP) {
498 double h0 = enthalpy();
499 double Tlow = 0.5*m_Tmin; // lower bound on T
500 double Thigh = 2.0*m_Tmax; // upper bound on T
501 double Hlow = Undef, Hhigh = Undef;
502 for (int n = 0; n < maxiter; n++) {
503 // if 'strt' is false, the current composition will be used as
504 // the starting estimate; otherwise it will be estimated
505 MultiPhaseEquil e(this, strt);
506 // start with a loose error tolerance, but tighten it as we get
507 // close to the final temperature
508
509 try {
510 e.equilibrate(TP, err, maxsteps, loglevel);
511 double hnow = enthalpy();
512 // the equilibrium enthalpy monotonically increases with T;
513 // if the current value is below the target, the we know the
514 // current temperature is too low. Set
515 if (hnow < h0) {
516 if (m_temp > Tlow) {
517 Tlow = m_temp;
518 Hlow = hnow;
519 }
520 } else {
521 // the current enthalpy is greater than the target;
522 // therefore the current temperature is too high.
523 if (m_temp < Thigh) {
524 Thigh = m_temp;
525 Hhigh = hnow;
526 }
527 }
528 double dt;
529 if (Hlow != Undef && Hhigh != Undef) {
530 double cpb = (Hhigh - Hlow)/(Thigh - Tlow);
531 dt = (h0 - hnow)/cpb;
532 dta = fabs(dt);
533 double dtmax = 0.5*fabs(Thigh - Tlow);
534 if (dta > dtmax) {
535 dt *= dtmax/dta;
536 }
537 } else {
538 double tnew = sqrt(Tlow*Thigh);
539 dt = tnew - m_temp;
540 }
541
542 double herr = fabs((h0 - hnow)/h0);
543
544 if (herr < err) {
545 return err;
546 }
547 double tnew = m_temp + dt;
548 if (tnew < 0.0) {
549 tnew = 0.5*m_temp;
550 }
551 setTemperature(tnew);
552
553 // if the size of Delta T is not too large, use
554 // the current composition as the starting estimate
555 if (dta < 100.0) {
556 strt = false;
557 }
558
559 } catch (CanteraError&) {
560 if (!strt) {
561 strt = true;
562 } else {
563 double tnew = 0.5*(m_temp + Thigh);
564 if (fabs(tnew - m_temp) < 1.0) {
565 tnew = m_temp + 1.0;
566 }
567 setTemperature(tnew);
568 }
569 }
570 }
571 throw CanteraError("MultiPhase::equilibrate_MultiPhaseEquil",
572 "No convergence for T");
573 } else if (XY == SP) {
574 double s0 = entropy();
575 double Tlow = 1.0; // lower bound on T
576 double Thigh = 1.0e6; // upper bound on T
577 for (int n = 0; n < maxiter; n++) {
578 MultiPhaseEquil e(this, strt);
579
580 try {
581 e.equilibrate(TP, err, maxsteps, loglevel);
582 double snow = entropy();
583 if (snow < s0) {
584 Tlow = std::max(Tlow, m_temp);
585 } else {
586 Thigh = std::min(Thigh, m_temp);
587 }
588 double dt = (s0 - snow)*m_temp/cp();
589 double dtmax = 0.5*fabs(Thigh - Tlow);
590 dtmax = (dtmax > 500.0 ? 500.0 : dtmax);
591 dta = fabs(dt);
592 if (dta > dtmax) {
593 dt *= dtmax/dta;
594 }
595 if (dta < 1.0e-4) {
596 return err;
597 }
598 double tnew = m_temp + dt;
599 setTemperature(tnew);
600
601 // if the size of Delta T is not too large, use
602 // the current composition as the starting estimate
603 if (dta < 100.0) {
604 strt = false;
605 }
606 } catch (CanteraError&) {
607 if (!strt) {
608 strt = true;
609 } else {
610 double tnew = 0.5*(m_temp + Thigh);
611 setTemperature(tnew);
612 }
613 }
614 }
615 throw CanteraError("MultiPhase::equilibrate_MultiPhaseEquil",
616 "No convergence for T");
617 } else if (XY == TV) {
618 double v0 = volume();
619 bool start = true;
620 for (int n = 0; n < maxiter; n++) {
621 double pnow = pressure();
622 MultiPhaseEquil e(this, start);
623 start = false;
624
625 e.equilibrate(TP, err, maxsteps, loglevel);
626 double vnow = volume();
627 double verr = fabs((v0 - vnow)/v0);
628
629 if (verr < err) {
630 return err;
631 }
632 // find dV/dP
633 setPressure(pnow*1.01);
634 double dVdP = (volume() - vnow)/(0.01*pnow);
635 setPressure(pnow + 0.5*(v0 - vnow)/dVdP);
636 }
637 } else {
638 throw CanteraError("MultiPhase::equilibrate_MultiPhaseEquil",
639 "unknown option");
640 }
641 return -1.0;
642}
643
644void MultiPhase::equilibrate(const string& XY, const string& solver,
645 double rtol, int max_steps, int max_iter,
646 int estimate_equil, int log_level)
647{
648 // Save the initial state so that it can be restored in case one of the
649 // solvers fails
650 vector<double> initial_moleFractions = m_moleFractions;
651 vector<double> initial_moles = m_moles;
652 double initial_T = m_temp;
653 double initial_P = m_press;
654 int ixy = _equilflag(XY.c_str());
655 if (solver == "auto" || solver == "vcs") {
656 try {
657 debuglog("Trying VCS equilibrium solver\n", log_level);
658 vcs_MultiPhaseEquil eqsolve(this, log_level-1);
659 int ret = eqsolve.equilibrate(ixy, estimate_equil, log_level-1,
660 rtol, max_steps);
661 if (ret) {
662 throw CanteraError("MultiPhase::equilibrate",
663 "VCS solver failed. Return code: {}", ret);
664 }
665 debuglog("VCS solver succeeded\n", log_level);
666 return;
667 } catch (std::exception& err) {
668 debuglog("VCS solver failed.\n", log_level);
669 debuglog(err.what(), log_level);
670 m_moleFractions = initial_moleFractions;
671 m_moles = initial_moles;
672 m_temp = initial_T;
673 m_press = initial_P;
674 updatePhases();
675 if (solver == "auto") {
676 } else {
677 throw;
678 }
679 }
680 }
681
682 if (solver == "auto" || solver == "gibbs") {
683 try {
684 debuglog("Trying MultiPhaseEquil (Gibbs) equilibrium solver\n",
685 log_level);
686 equilibrate_MultiPhaseEquil(ixy, rtol, max_steps, max_iter,
687 log_level-1);
688 debuglog("MultiPhaseEquil solver succeeded\n", log_level);
689 return;
690 } catch (std::exception& err) {
691 debuglog("MultiPhaseEquil solver failed.\n", log_level);
692 debuglog(err.what(), log_level);
693 m_moleFractions = initial_moleFractions;
694 m_moles = initial_moles;
695 m_temp = initial_T;
696 m_press = initial_P;
697 updatePhases();
698 throw;
699 }
700 }
701
702 if (solver != "auto") {
703 throw CanteraError("MultiPhase::equilibrate",
704 "Invalid solver specified: '" + solver + "'");
705 }
706}
707
708void MultiPhase::setTemperature(const double T)
709{
710 if (!m_init) {
711 init();
712 }
713 m_temp = T;
714 updatePhases();
715}
716
717size_t MultiPhase::checkElementIndex(size_t m) const
718{
719 if (m < m_nel) {
720 return m;
721 }
722 throw IndexError("MultiPhase::checkElementIndex", "elements", m, m_nel);
723}
724
726{
727 warn_deprecated("MultiPhase::checkElementArraySize",
728 "To be removed after Cantera 3.2. Only used by legacy CLib.");
729 if (m_nel > mm) {
730 throw ArraySizeError("MultiPhase::checkElementArraySize", mm, m_nel);
731 }
732}
733
734string MultiPhase::elementName(size_t m) const
735{
736 if (m < m_nel) {
737 return m_enames[m];
738 }
739 throw IndexError("MultiPhase::elementName", "element", m, m_nel);
740}
741
742size_t MultiPhase::elementIndex(const string& name) const
743{
744 size_t ix = elementIndex(name, false);
745 if (ix == npos) {
746 warn_deprecated("MultiPhase::elementIndex", "'raise' argument not specified; "
747 "Default behavior will change from returning npos to throwing an exception "
748 "after Cantera 3.2.");
749 }
750 return ix;
751}
752
753size_t MultiPhase::elementIndex(const string& name, bool raise) const
754{
755 for (size_t e = 0; e < m_nel; e++) {
756 if (m_enames[e] == name) {
757 return e;
758 }
759 }
760 if (!raise) {
761 return npos;
762 }
763 throw CanteraError("MultiPhase::elementIndex", "Element '{}' not found", name);
764}
765
766size_t MultiPhase::checkSpeciesIndex(size_t k) const
767{
768 if (k < m_nsp) {
769 return k;
770 }
771 throw IndexError("MultiPhase::checkSpeciesIndex", "species", k, m_nsp);
772}
773
775{
776 warn_deprecated("MultiPhase::checkSpeciesArraySize",
777 "To be removed after Cantera 3.2. Only used by legacy CLib.");
778 if (m_nsp > kk) {
779 throw ArraySizeError("MultiPhase::checkSpeciesArraySize", kk, m_nsp);
780 }
781}
782
783string MultiPhase::speciesName(size_t k) const
784{
785 if (k < m_nsp) {
786 return m_snames[k];
787 }
788 throw IndexError("MultiPhase::speciesName", "species", k, m_nsp);
789}
790
791double MultiPhase::nAtoms(const size_t kGlob, const size_t mGlob) const
792{
793 return m_atoms(mGlob, kGlob);
794}
795
796void MultiPhase::getMoleFractions(double* const x) const
797{
798 std::copy(m_moleFractions.begin(), m_moleFractions.end(), x);
799}
800
801string MultiPhase::phaseName(size_t iph) const
802{
803 if (iph < m_phase.size()) {
804 return m_phase[iph]->name();
805 }
806 throw IndexError("MultiPhase::phaseName", "phase", iph, m_phase.size());
807}
808
809int MultiPhase::phaseIndex(const string& pName) const
810{
811 size_t ix = phaseIndex(pName, false);
812 if (ix == npos) {
813 warn_deprecated("MultiPhase::phaseIndex", "'raise' argument not specified; "
814 "Default behavior will change from returning -1 to throwing an exception "
815 "after Cantera 3.2. 'npos' will be return instead of -1 if 'raise=true'.");
816 }
817 return ix;
818}
819
820size_t MultiPhase::phaseIndex(const string& pName, bool raise) const
821{
822 for (int iph = 0; iph < (int) nPhases(); iph++) {
823 if (m_phase[iph]->name() == pName) {
824 return iph;
825 }
826 }
827 if (!raise) {
828 return npos;
829 }
830 throw CanteraError("MultiPhase::phaseIndex", "Phase '{}' not found", pName);
831}
832
833double MultiPhase::phaseMoles(const size_t n) const
834{
835 return m_moles[n];
836}
837
838void MultiPhase::setPhaseMoles(const size_t n, const double moles)
839{
840 m_moles[n] = moles;
841}
842
843size_t MultiPhase::speciesPhaseIndex(const size_t kGlob) const
844{
845 return m_spphase[kGlob];
846}
847
848double MultiPhase::moleFraction(const size_t kGlob) const
849{
850 return m_moleFractions[kGlob];
851}
852
853bool MultiPhase::tempOK(const size_t p) const
854{
855 return m_temp_OK[p];
856}
857
859{
860 size_t loc = 0;
861 for (size_t ip = 0; ip < nPhases(); ip++) {
862 ThermoPhase* p = m_phase[ip];
863 p->getMoleFractions(m_moleFractions.data() + loc);
864 loc += p->nSpecies();
865 }
867}
868
870{
871 size_t loc = 0;
872 for (size_t p = 0; p < nPhases(); p++) {
873 m_phase[p]->setState_TPX(m_temp, m_press, m_moleFractions.data() + loc);
874 loc += m_phase[p]->nSpecies();
875 m_temp_OK[p] = true;
876 if (m_temp < m_phase[p]->minTemp() || m_temp > m_phase[p]->maxTemp()) {
877 m_temp_OK[p] = false;
878 }
879 }
880}
881
882std::ostream& operator<<(std::ostream& s, MultiPhase& x)
883{
884 x.updatePhases();
885 for (size_t ip = 0; ip < x.nPhases(); ip++) {
886 if (x.phase(ip).name() != "") {
887 s << "*************** " << x.phase(ip).name() << " *****************" << std::endl;
888 } else {
889 s << "*************** Phase " << ip << " *****************" << std::endl;
890 }
891 s << "Moles: " << x.phaseMoles(ip) << std::endl;
892
893 s << x.phase(ip).report() << std::endl;
894 }
895 return s;
896}
897
898}
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,...
Array size error.
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:282
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:627
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:640
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:685
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:679
void calcElemAbundances() const
Calculate the element abundance vector.
size_t nSpecies() const
Number of species, summed over all phases.
Definition MultiPhase.h:157
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:444
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:659
vector< size_t > m_spphase
Mapping between the global species number and the phase ID.
Definition MultiPhase.h:651
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:302
vector< double > m_moleFractions
Locally stored vector of mole fractions of all species comprising the MultiPhase object.
Definition MultiPhase.h:644
vector< double > m_elemAbundances
Vector of element abundances.
Definition MultiPhase.h:717
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.
void checkPhaseArraySize(size_t mm) const
Check that an array size is at least nPhases() Throws an exception if mm is less than nPhases().
vector< bool > m_temp_OK
Vector of bools indicating whether temperatures are ok for phases.
Definition MultiPhase.h:702
double phaseCharge(size_t p) const
Charge (Coulombs) of phase with index p.
int phaseIndex(const string &pName) const
Returns the index, given the phase name.
size_t nPhases() const
Number of phases.
Definition MultiPhase.h:481
size_t m_eloc
Global ID of the element corresponding to the electronic charge.
Definition MultiPhase.h:695
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:682
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:676
vector< shared_ptr< ThermoPhase > > m_sharedPhase
Vector of shared ThermoPhase pointers.
Definition MultiPhase.h:632
void addSpeciesMoles(const int indexS, const double addedMoles)
Adds moles of a certain species to the mixture.
size_t elementIndex(const string &name) const
Returns the index of the element with name name.
void checkElementArraySize(size_t mm) const
Check that an array size is at least nElements().
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:459
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:663
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:688
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:666
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:691
vector< string > m_snames
Vector of species names in the problem.
Definition MultiPhase.h:670
double m_Tmin
Minimum temperature for which thermo parameterizations are valid.
Definition MultiPhase.h:706
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.
void checkSpeciesArraySize(size_t kk) const
Check that an array size is at least nSpecies().
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].
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:624
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:710
virtual ~MultiPhase()
Destructor.
size_t nSpecies() const
Returns the number of species in the phase.
Definition Phase.h:270
int atomicNumber(size_t m) const
Atomic number of element m.
Definition Phase.cpp:104
double temperature() const
Temperature (K).
Definition Phase.h:629
void addSpeciesLock()
Lock species list to prevent addition of new species.
Definition Phase.h:787
size_t elementIndex(const string &name) const
Return the index of element named 'name'.
Definition Phase.cpp:60
string speciesName(size_t k) const
Name of the species with index k.
Definition Phase.cpp:174
void getMoleFractions(double *const x) const
Get the species mole fraction vector.
Definition Phase.cpp:499
double nAtoms(size_t k, size_t m) const
Number of atoms of element m in species k.
Definition Phase.cpp:121
size_t nElements() const
Number of elements.
Definition Phase.cpp:30
virtual double pressure() const
Return the thermodynamic pressure (Pa).
Definition Phase.h:647
string elementName(size_t m) const
Name of the element with index m.
Definition Phase.cpp:52
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:159
const double Faraday
Faraday constant [C/kmol].
Definition ct_defs.h:131
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:180
const double Undef
Fairly random number to be used to initialize variables against to see if they are subsequently defin...
Definition ct_defs.h:164
int _equilflag(const char *xy)
map property strings to integers
Definition ChemEquil.cpp:20
void warn_deprecated(const string &source, const AnyBase &node, const string &message)
A deprecation warning for syntax in an input file.
Definition AnyMap.cpp:1997
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:177
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.