Cantera  3.3.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
475double MultiPhase::equilibrate_MultiPhaseEquil(int XY, double err, int maxsteps,
476 int maxiter, int loglevel)
477{
478 bool strt = false;
479 double dta = 0.0;
480 if (!m_init) {
481 init();
482 }
483
484 if (XY == TP) {
485 // create an equilibrium manager
486 MultiPhaseEquil e(this);
487 return e.equilibrate(XY, err, maxsteps, loglevel);
488 } else if (XY == HP) {
489 double h0 = enthalpy();
490 double Tlow = 0.5*m_Tmin; // lower bound on T
491 double Thigh = 2.0*m_Tmax; // upper bound on T
492 double Hlow = Undef, Hhigh = Undef;
493 for (int n = 0; n < maxiter; n++) {
494 // if 'strt' is false, the current composition will be used as
495 // the starting estimate; otherwise it will be estimated
496 MultiPhaseEquil e(this, strt);
497 // start with a loose error tolerance, but tighten it as we get
498 // close to the final temperature
499
500 try {
501 e.equilibrate(TP, err, maxsteps, loglevel);
502 double hnow = enthalpy();
503 // the equilibrium enthalpy monotonically increases with T;
504 // if the current value is below the target, the we know the
505 // current temperature is too low. Set
506 if (hnow < h0) {
507 if (m_temp > Tlow) {
508 Tlow = m_temp;
509 Hlow = hnow;
510 }
511 } else {
512 // the current enthalpy is greater than the target;
513 // therefore the current temperature is too high.
514 if (m_temp < Thigh) {
515 Thigh = m_temp;
516 Hhigh = hnow;
517 }
518 }
519 double dt;
520 if (Hlow != Undef && Hhigh != Undef) {
521 double cpb = (Hhigh - Hlow)/(Thigh - Tlow);
522 dt = (h0 - hnow)/cpb;
523 dta = fabs(dt);
524 double dtmax = 0.5*fabs(Thigh - Tlow);
525 if (dta > dtmax) {
526 dt *= dtmax/dta;
527 }
528 } else {
529 double tnew = sqrt(Tlow*Thigh);
530 dt = tnew - m_temp;
531 }
532
533 double herr = fabs((h0 - hnow)/h0);
534
535 if (herr < err) {
536 return err;
537 }
538 double tnew = m_temp + dt;
539 if (tnew < 0.0) {
540 tnew = 0.5*m_temp;
541 }
542 setTemperature(tnew);
543
544 // if the size of Delta T is not too large, use
545 // the current composition as the starting estimate
546 if (dta < 100.0) {
547 strt = false;
548 }
549
550 } catch (CanteraError&) {
551 if (!strt) {
552 strt = true;
553 } else {
554 double tnew = 0.5*(m_temp + Thigh);
555 if (fabs(tnew - m_temp) < 1.0) {
556 tnew = m_temp + 1.0;
557 }
558 setTemperature(tnew);
559 }
560 }
561 }
562 throw CanteraError("MultiPhase::equilibrate_MultiPhaseEquil",
563 "No convergence for T");
564 } else if (XY == SP) {
565 double s0 = entropy();
566 double Tlow = 1.0; // lower bound on T
567 double Thigh = 1.0e6; // upper bound on T
568 for (int n = 0; n < maxiter; n++) {
569 MultiPhaseEquil e(this, strt);
570
571 try {
572 e.equilibrate(TP, err, maxsteps, loglevel);
573 double snow = entropy();
574 if (snow < s0) {
575 Tlow = std::max(Tlow, m_temp);
576 } else {
577 Thigh = std::min(Thigh, m_temp);
578 }
579 double dt = (s0 - snow)*m_temp/cp();
580 double dtmax = 0.5*fabs(Thigh - Tlow);
581 dtmax = (dtmax > 500.0 ? 500.0 : dtmax);
582 dta = fabs(dt);
583 if (dta > dtmax) {
584 dt *= dtmax/dta;
585 }
586 if (dta < 1.0e-4) {
587 return err;
588 }
589 double tnew = m_temp + dt;
590 setTemperature(tnew);
591
592 // if the size of Delta T is not too large, use
593 // the current composition as the starting estimate
594 if (dta < 100.0) {
595 strt = false;
596 }
597 } catch (CanteraError&) {
598 if (!strt) {
599 strt = true;
600 } else {
601 double tnew = 0.5*(m_temp + Thigh);
602 setTemperature(tnew);
603 }
604 }
605 }
606 throw CanteraError("MultiPhase::equilibrate_MultiPhaseEquil",
607 "No convergence for T");
608 } else if (XY == TV) {
609 double v0 = volume();
610 bool start = true;
611 for (int n = 0; n < maxiter; n++) {
612 double pnow = pressure();
613 MultiPhaseEquil e(this, start);
614 start = false;
615
616 e.equilibrate(TP, err, maxsteps, loglevel);
617 double vnow = volume();
618 double verr = fabs((v0 - vnow)/v0);
619
620 if (verr < err) {
621 return err;
622 }
623 // find dV/dP
624 setPressure(pnow*1.01);
625 double dVdP = (volume() - vnow)/(0.01*pnow);
626 setPressure(pnow + 0.5*(v0 - vnow)/dVdP);
627 }
628 } else {
629 throw CanteraError("MultiPhase::equilibrate_MultiPhaseEquil",
630 "unknown option");
631 }
632 return -1.0;
633}
634
635void MultiPhase::equilibrate(const string& XY, const string& solver,
636 double rtol, int max_steps, int max_iter,
637 int estimate_equil, int log_level)
638{
639 // Save the initial state so that it can be restored in case one of the
640 // solvers fails
641 vector<double> initial_moleFractions = m_moleFractions;
642 vector<double> initial_moles = m_moles;
643 double initial_T = m_temp;
644 double initial_P = m_press;
645 int ixy = _equilflag(XY.c_str());
646 if (solver == "auto" || solver == "vcs") {
647 try {
648 debuglog("Trying VCS equilibrium solver\n", log_level);
649 vcs_MultiPhaseEquil eqsolve(this, log_level-1);
650 int ret = eqsolve.equilibrate(ixy, estimate_equil, log_level-1,
651 rtol, max_steps);
652 if (ret) {
653 throw CanteraError("MultiPhase::equilibrate",
654 "VCS solver failed. Return code: {}", ret);
655 }
656 debuglog("VCS solver succeeded\n", log_level);
657 return;
658 } catch (std::exception& err) {
659 debuglog("VCS solver failed.\n", log_level);
660 debuglog(err.what(), log_level);
661 m_moleFractions = initial_moleFractions;
662 m_moles = initial_moles;
663 m_temp = initial_T;
664 m_press = initial_P;
665 updatePhases();
666 if (solver == "auto") {
667 } else {
668 throw;
669 }
670 }
671 }
672
673 if (solver == "auto" || solver == "gibbs") {
674 try {
675 debuglog("Trying MultiPhaseEquil (Gibbs) equilibrium solver\n",
676 log_level);
677 equilibrate_MultiPhaseEquil(ixy, rtol, max_steps, max_iter,
678 log_level-1);
679 debuglog("MultiPhaseEquil solver succeeded\n", log_level);
680 return;
681 } catch (std::exception& err) {
682 debuglog("MultiPhaseEquil solver failed.\n", log_level);
683 debuglog(err.what(), log_level);
684 m_moleFractions = initial_moleFractions;
685 m_moles = initial_moles;
686 m_temp = initial_T;
687 m_press = initial_P;
688 updatePhases();
689 throw;
690 }
691 }
692
693 if (solver != "auto") {
694 throw CanteraError("MultiPhase::equilibrate",
695 "Invalid solver specified: '" + solver + "'");
696 }
697}
698
699void MultiPhase::setTemperature(const double T)
700{
701 if (!m_init) {
702 init();
703 }
704 m_temp = T;
705 updatePhases();
706}
707
708size_t MultiPhase::checkElementIndex(size_t m) const
709{
710 if (m < m_nel) {
711 return m;
712 }
713 throw IndexError("MultiPhase::checkElementIndex", "elements", m, m_nel);
714}
715
716string MultiPhase::elementName(size_t m) const
717{
718 if (m < m_nel) {
719 return m_enames[m];
720 }
721 throw IndexError("MultiPhase::elementName", "element", m, m_nel);
722}
723
724size_t MultiPhase::elementIndex(const string& name, bool raise) const
725{
726 for (size_t e = 0; e < m_nel; e++) {
727 if (m_enames[e] == name) {
728 return e;
729 }
730 }
731 if (!raise) {
732 return npos;
733 }
734 throw CanteraError("MultiPhase::elementIndex", "Element '{}' not found", name);
735}
736
737size_t MultiPhase::checkSpeciesIndex(size_t k) const
738{
739 if (k < m_nsp) {
740 return k;
741 }
742 throw IndexError("MultiPhase::checkSpeciesIndex", "species", k, m_nsp);
743}
744
745string MultiPhase::speciesName(size_t k) const
746{
747 if (k < m_nsp) {
748 return m_snames[k];
749 }
750 throw IndexError("MultiPhase::speciesName", "species", k, m_nsp);
751}
752
753double MultiPhase::nAtoms(const size_t kGlob, const size_t mGlob) const
754{
755 return m_atoms(mGlob, kGlob);
756}
757
758void MultiPhase::getMoleFractions(double* const x) const
759{
760 std::copy(m_moleFractions.begin(), m_moleFractions.end(), x);
761}
762
763string MultiPhase::phaseName(size_t iph) const
764{
765 if (iph < m_phase.size()) {
766 return m_phase[iph]->name();
767 }
768 throw IndexError("MultiPhase::phaseName", "phase", iph, m_phase.size());
769}
770
771size_t MultiPhase::phaseIndex(const string& pName, bool raise) const
772{
773 for (int iph = 0; iph < (int) nPhases(); iph++) {
774 if (m_phase[iph]->name() == pName) {
775 return iph;
776 }
777 }
778 if (!raise) {
779 return npos;
780 }
781 throw CanteraError("MultiPhase::phaseIndex", "Phase '{}' not found", pName);
782}
783
784double MultiPhase::phaseMoles(const size_t n) const
785{
786 return m_moles[n];
787}
788
789void MultiPhase::setPhaseMoles(const size_t n, const double moles)
790{
791 m_moles[n] = moles;
792}
793
794size_t MultiPhase::speciesPhaseIndex(const size_t kGlob) const
795{
796 return m_spphase[kGlob];
797}
798
799double MultiPhase::moleFraction(const size_t kGlob) const
800{
801 return m_moleFractions[kGlob];
802}
803
804bool MultiPhase::tempOK(const size_t p) const
805{
806 return m_temp_OK[p];
807}
808
810{
811 size_t loc = 0;
812 for (size_t ip = 0; ip < nPhases(); ip++) {
813 ThermoPhase* p = m_phase[ip];
814 p->getMoleFractions(m_moleFractions.data() + loc);
815 loc += p->nSpecies();
816 }
818}
819
821{
822 size_t loc = 0;
823 for (size_t p = 0; p < nPhases(); p++) {
824 m_phase[p]->setState_TPX(m_temp, m_press, m_moleFractions.data() + loc);
825 loc += m_phase[p]->nSpecies();
826 m_temp_OK[p] = true;
827 if (m_temp < m_phase[p]->minTemp() || m_temp > m_phase[p]->maxTemp()) {
828 m_temp_OK[p] = false;
829 }
830 }
831}
832
833std::ostream& operator<<(std::ostream& s, MultiPhase& x)
834{
835 x.updatePhases();
836 for (size_t ip = 0; ip < x.nPhases(); ip++) {
837 if (x.phase(ip).name() != "") {
838 s << "*************** " << x.phase(ip).name() << " *****************" << std::endl;
839 } else {
840 s << "*************** Phase " << ip << " *****************" << std::endl;
841 }
842 s << "Moles: " << x.phaseMoles(ip) << std::endl;
843
844 s << x.phase(ip).report() << std::endl;
845 }
846 return s;
847}
848
849}
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: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.