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