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