Cantera  3.3.0a1
Loading...
Searching...
No Matches
Phase.cpp
Go to the documentation of this file.
1/**
2 * @file Phase.cpp
3 * Definition file for class Phase.
4 */
5
6// This file is part of Cantera. See License.txt in the top-level directory or
7// at https://cantera.org/license.txt for license and copyright information.
8
14
15using namespace std;
16
17namespace Cantera
18{
19
20string Phase::name() const
21{
22 return m_name;
23}
24
25void Phase::setName(const string& name)
26{
27 m_name = name;
28}
29
30size_t Phase::nElements() const
31{
32 return m_mm;
33}
34
35size_t Phase::checkElementIndex(size_t m) const
36{
37 if (m < m_mm) {
38 return m;
39 }
40 throw IndexError("Phase::checkElementIndex", "elements", m, m_mm);
41}
42
43string Phase::elementName(size_t m) const
44{
45 if (m < m_mm) {
46 return m_elementNames[m];
47 }
48 throw IndexError("Phase::elementName", "element", m, m_mm);
49}
50
51size_t Phase::elementIndex(const string& elementName, bool raise) const
52{
53 for (size_t i = 0; i < m_mm; i++) {
54 if (m_elementNames[i] == elementName) {
55 return i;
56 }
57 }
58 if (!raise) {
59 return npos;
60 }
61 throw CanteraError("Phase::elementIndex", "Element '{}' not found", elementName);
62}
63
64const vector<string>& Phase::elementNames() const
65{
66 return m_elementNames;
67}
68
69double Phase::atomicWeight(size_t m) const
70{
71 return m_atomicWeights[m];
72}
73
74double Phase::entropyElement298(size_t m) const
75{
77}
78
79const vector<double>& Phase::atomicWeights() const
80{
81 return m_atomicWeights;
82}
83
84int Phase::atomicNumber(size_t m) const
85{
86 return m_atomicNumbers[m];
87}
88
89int Phase::elementType(size_t m) const
90{
91 return m_elem_type[m];
92}
93
94int Phase::changeElementType(int m, int elem_type)
95{
96 int old = m_elem_type[m];
97 m_elem_type[m] = elem_type;
98 return old;
99}
100
101double Phase::nAtoms(size_t k, size_t m) const
102{
105 return m_speciesComp[m_mm * k + m];
106}
107
108size_t Phase::findSpeciesLower(const string& name) const
109{
110 string nLower = toLowerCopy(name);
111 size_t loc = npos;
112 auto it = m_speciesLower.find(nLower);
113 if (it == m_speciesLower.end()) {
114 return npos;
115 } else {
116 loc = it->second;
117 if (loc == npos) {
118 throw CanteraError("Phase::findSpeciesLower",
119 "Lowercase species name '{}' is not unique. "
120 "Set Phase::caseSensitiveSpecies to true to "
121 "enforce case sensitive species names", nLower);
122 }
123 }
124 return loc;
125}
126
127size_t Phase::speciesIndex(const string& name, bool raise) const
128{
129 size_t loc = npos;
130 auto it = m_speciesIndices.find(name);
131 if (it != m_speciesIndices.end()) {
132 return it->second;
133 } else if (!m_caseSensitiveSpecies) {
134 loc = findSpeciesLower(name);
135 }
136 if (loc==npos && raise) {
137 throw CanteraError("Phase::speciesIndex", "Species '{}' not found", name);
138 }
139
140 return loc;
141}
142
143string Phase::speciesName(size_t k) const
144{
145 if (k < m_kk) {
146 return m_speciesNames[k];
147 }
148 throw IndexError("Phase::speciesName", "species", k, m_kk);
149}
150
151const vector<string>& Phase::speciesNames() const
152{
153 return m_speciesNames;
154}
155
156size_t Phase::checkSpeciesIndex(size_t k) const
157{
158 if (k < m_kk) {
159 return k;
160 }
161 throw IndexError("Phase::checkSpeciesIndex", "species", k, m_kk);
162}
163
164map<string, size_t> Phase::nativeState() const
165{
166 if (isPure()) {
167 if (isCompressible()) {
168 return { {"T", 0}, {"D", 1} };
169 } else {
170 return { {"T", 0}, {"P", 1} };
171 }
172 } else {
173 if (isCompressible()) {
174 return { {"T", 0}, {"D", 1}, {"Y", 2} };
175 } else {
176 return { {"T", 0}, {"P", 1}, {"Y", 2} };
177 }
178 }
179}
180
181string Phase::nativeMode() const
182{
183 map<size_t, string> states; // reverse lookup
184 for (auto& [name, value] : nativeState()) {
185 states[value] = name;
186 }
187 string out;
188 for (auto& [value, name] : states) {
189 out += name;
190 }
191 return out;
192}
193
194vector<string> Phase::fullStates() const
195{
196 if (isPure()) {
197 if (isCompressible()) {
198 return {"TD", "TP", "UV", "DP", "HP", "SP", "SV"};
199 } else {
200 return {"TP", "HP", "SP"};
201 }
202 } else {
203 if (isCompressible()) {
204 return {"TDX", "TDY", "TPX", "TPY", "UVX", "UVY", "DPX", "DPY",
205 "HPX", "HPY", "SPX", "SPY", "SVX", "SVY"};
206 } else {
207 return {"TPX", "TPY", "HPX", "HPY", "SPX", "SPY"};
208 }
209 }
210}
211
212vector<string> Phase::partialStates() const
213{
214 if (isPure()) {
215 return {};
216 } else {
217 if (isCompressible()) {
218 return {"TD", "TP", "UV", "DP", "HP", "SP", "SV"};
219 } else {
220 return {"TP", "HP", "SP"};
221 }
222 }
223}
224
225void Phase::savePartialState(size_t lenstate, double* state) const
226{
227 if (lenstate < partialStateSize()) {
228 throw ArraySizeError("Phase::savePartialState", lenstate, partialStateSize());
229 }
230
231 auto native = nativeState();
232 state[native.at("T")] = temperature();
233 if (isCompressible()) {
234 state[native.at("D")] = density();
235 } else {
236 state[native.at("P")] = pressure();
237 }
238}
239
240void Phase::restorePartialState(size_t lenstate, const double* state)
241{
242 if (lenstate < partialStateSize()) {
243 throw ArraySizeError("Phase::restorePartialState", lenstate, partialStateSize());
244 }
245
246 auto native = nativeState();
247 setTemperature(state[native.at("T")]);
248 if (isCompressible()) {
249 setDensity(state[native.at("D")]);
250 } else {
251 setPressure(state[native.at("P")]);
252 }
253}
254
255size_t Phase::stateSize() const {
256 if (isPure()) {
257 return partialStateSize();
258 } else {
259 return partialStateSize() + nSpecies();
260 }
261}
262
263void Phase::saveState(vector<double>& state) const
264{
265 state.resize(stateSize());
266 saveState(state.size(), &state[0]);
267}
268
269void Phase::saveState(size_t lenstate, double* state) const
270{
271 if (lenstate < stateSize()) {
272 throw ArraySizeError("Phase::saveState", lenstate, stateSize());
273 }
274 savePartialState(lenstate, state);
275 auto native = nativeState();
276 if (native.count("X")) {
277 getMoleFractions(state + native["X"]);
278 } else if (native.count("Y")) {
279 getMassFractions(state + native["Y"]);
280 }
281}
282
283void Phase::restoreState(const vector<double>& state)
284{
285 restoreState(state.size(),&state[0]);
286}
287
288void Phase::restoreState(size_t lenstate, const double* state)
289{
290 size_t ls = stateSize();
291 if (lenstate < ls) {
292 throw ArraySizeError("Phase::restoreState",
293 lenstate, ls);
294 }
295 restorePartialState(lenstate, state);
296
297 auto native = nativeState();
298
299 if (native.count("X")) {
300 setMoleFractions_NoNorm(state + native["X"]);
301 } else if (native.count("Y")) {
302 setMassFractions_NoNorm(state + native["Y"]);
303 }
305}
306
307void Phase::setMoleFractions(const double* const x)
308{
309 // Use m_y as a temporary work vector for the non-negative mole fractions
310 double norm = 0.0;
311 // sum is calculated below as the unnormalized molecular weight
312 double sum = 0;
313 for (size_t k = 0; k < m_kk; k++) {
314 double xk = std::max(x[k], 0.0); // Ignore negative mole fractions
315 m_y[k] = xk;
316 norm += xk;
317 sum += m_molwts[k] * xk;
318 }
319
320 // Set m_ym to the normalized mole fractions divided by the normalized mean
321 // molecular weight:
322 // m_ym_k = X_k / (sum_k X_k M_k)
323 const double invSum = 1.0/sum;
324 for (size_t k=0; k < m_kk; k++) {
325 m_ym[k] = m_y[k]*invSum;
326 }
327
328 // Now set m_y to the normalized mass fractions:
329 // m_y = X_k M_k / (sum_k X_k M_k)
330 for (size_t k=0; k < m_kk; k++) {
331 m_y[k] = m_ym[k] * m_molwts[k];
332 }
333
334 // Calculate the normalized molecular weight
335 m_mmw = sum/norm;
337}
338
339void Phase::setMoleFractions_NoNorm(const double* const x)
340{
341 m_mmw = dot(x, x + m_kk, m_molwts.begin());
342 scale(x, x + m_kk, m_ym.begin(), 1.0/m_mmw);
343 transform(m_ym.begin(), m_ym.begin() + m_kk, m_molwts.begin(),
344 m_y.begin(), multiplies<double>());
346}
347
349{
350 vector<double> mf = getCompositionFromMap(xMap);
351 setMoleFractions(mf.data());
352}
353
354void Phase::setMoleFractionsByName(const string& x)
355{
357}
358
359void Phase::setMassFractions(const double* const y)
360{
361 for (size_t k = 0; k < m_kk; k++) {
362 m_y[k] = std::max(y[k], 0.0); // Ignore negative mass fractions
363 }
364 double norm = accumulate(m_y.begin(), m_y.end(), 0.0);
365 scale(m_y.begin(), m_y.end(), m_y.begin(), 1.0/norm);
366
367 transform(m_y.begin(), m_y.end(), m_rmolwts.begin(),
368 m_ym.begin(), multiplies<double>());
369 m_mmw = 1.0 / accumulate(m_ym.begin(), m_ym.end(), 0.0);
371}
372
373void Phase::setMassFractions_NoNorm(const double* const y)
374{
375 double sum = 0.0;
376 copy(y, y + m_kk, m_y.begin());
377 transform(m_y.begin(), m_y.end(), m_rmolwts.begin(), m_ym.begin(),
378 multiplies<double>());
379 sum = accumulate(m_ym.begin(), m_ym.end(), 0.0);
380 m_mmw = 1.0/sum;
382}
383
385{
386 vector<double> mf = getCompositionFromMap(yMap);
387 setMassFractions(mf.data());
388}
389
390void Phase::setMassFractionsByName(const string& y)
391{
393}
394
395void Phase::setState_TD(double t, double rho)
396{
397 vector<double> state(partialStateSize());
398 savePartialState(state.size(), state.data());
399 try {
401 setDensity(rho);
402 } catch (std::exception&) {
403 restorePartialState(state.size(), state.data());
404 throw;
405 }
406}
407
408double Phase::molecularWeight(size_t k) const
409{
411 return m_molwts[k];
412}
413
414void Phase::getMolecularWeights(double* weights) const
415{
416 const vector<double>& mw = molecularWeights();
417 copy(mw.begin(), mw.end(), weights);
418}
419
420const vector<double>& Phase::molecularWeights() const
421{
422 return m_molwts;
423}
424
425const vector<double>& Phase::inverseMolecularWeights() const
426{
427 return m_rmolwts;
428}
429
430void Phase::getCharges(double* charges) const
431{
432 copy(m_speciesCharge.begin(), m_speciesCharge.end(), charges);
433}
434
436{
437 Composition comp;
438 for (size_t k = 0; k < m_kk; k++) {
439 double x = moleFraction(k);
440 if (x > threshold) {
441 comp[speciesName(k)] = x;
442 }
443 }
444 return comp;
445}
446
448{
449 Composition comp;
450 for (size_t k = 0; k < m_kk; k++) {
451 double x = massFraction(k);
452 if (x > threshold) {
453 comp[speciesName(k)] = x;
454 }
455 }
456 return comp;
457}
458
459void Phase::getMoleFractions(double* const x) const
460{
461 scale(m_ym.begin(), m_ym.end(), x, m_mmw);
462}
463
464double Phase::moleFraction(size_t k) const
465{
467 return m_ym[k] * m_mmw;
468}
469
470double Phase::moleFraction(const string& nameSpec) const
471{
472 size_t iloc = speciesIndex(nameSpec, false);
473 if (iloc != npos) {
474 return moleFraction(iloc);
475 } else {
476 return 0.0;
477 }
478}
479
480double Phase::massFraction(size_t k) const
481{
483 return m_y[k];
484}
485
486double Phase::massFraction(const string& nameSpec) const
487{
488 size_t iloc = speciesIndex(nameSpec, false);
489 if (iloc != npos) {
490 return massFractions()[iloc];
491 } else {
492 return 0.0;
493 }
494}
495
496void Phase::getMassFractions(double* const y) const
497{
498 copy(m_y.begin(), m_y.end(), y);
499}
500
501double Phase::concentration(const size_t k) const
502{
504 return m_y[k] * m_dens * m_rmolwts[k];
505}
506
507void Phase::getConcentrations(double* const c) const
508{
509 scale(m_ym.begin(), m_ym.end(), c, m_dens);
510}
511
512void Phase::setConcentrations(const double* const conc)
513{
514 assertCompressible("setConcentrations");
515
516 // Use m_y as temporary storage for non-negative concentrations
517 double sum = 0.0, norm = 0.0;
518 for (size_t k = 0; k != m_kk; ++k) {
519 double ck = std::max(conc[k], 0.0); // Ignore negative concentrations
520 m_y[k] = ck;
521 sum += ck * m_molwts[k];
522 norm += ck;
523 }
524 m_mmw = sum/norm;
525 setDensity(sum);
526 double rsum = 1.0/sum;
527 for (size_t k = 0; k != m_kk; ++k) {
528 m_ym[k] = m_y[k] * rsum;
529 m_y[k] = m_ym[k] * m_molwts[k]; // m_y is now the mass fraction
530 }
532}
533
534void Phase::setConcentrationsNoNorm(const double* const conc)
535{
536 assertCompressible("setConcentrationsNoNorm");
537
538 double sum = 0.0, norm = 0.0;
539 for (size_t k = 0; k != m_kk; ++k) {
540 sum += conc[k] * m_molwts[k];
541 norm += conc[k];
542 }
543 m_mmw = sum/norm;
544 setDensity(sum);
545 double rsum = 1.0/sum;
546 for (size_t k = 0; k != m_kk; ++k) {
547 m_ym[k] = conc[k] * rsum;
548 m_y[k] = m_ym[k] * m_molwts[k];
549 }
551}
552
553void Phase::setMolesNoTruncate(const double* const N)
554{
555 // get total moles
556 copy(N, N + m_kk, m_ym.begin());
557 double totalMoles = accumulate(m_ym.begin(), m_ym.end(), 0.0);
558 // get total mass
559 copy(N, N + m_kk, m_y.begin());
560 transform(m_y.begin(), m_y.end(), m_molwts.begin(), m_y.begin(), multiplies<double>());
561 double totalMass = accumulate(m_y.begin(), m_y.end(), 0.0);
562 // mean molecular weight
563 m_mmw = totalMass/totalMoles;
564 // mass fractions
565 scale(m_y.begin(), m_y.end(), m_y.begin(), 1/totalMass);
566 // moles fractions/m_mmw
567 scale(m_ym.begin(), m_ym.end(), m_ym.begin(), 1/(m_mmw * totalMoles));
568 // composition has changed
570}
571
572double Phase::elementalMassFraction(const size_t m) const
573{
574 double Z_m = 0.0;
575 for (size_t k = 0; k != m_kk; ++k) {
576 Z_m += nAtoms(k, m) * atomicWeight(m) / molecularWeight(k)
577 * massFraction(k);
578 }
579 return Z_m;
580}
581
582double Phase::elementalMoleFraction(const size_t m) const
583{
584 double denom = 0;
585 for (size_t k = 0; k < m_kk; k++) {
586 double atoms = 0;
587 for (size_t j = 0; j < nElements(); j++) {
588 atoms += nAtoms(k, j);
589 }
590 denom += atoms * moleFraction(k);
591 }
592 double numerator = 0.0;
593 for (size_t k = 0; k != m_kk; ++k) {
594 numerator += nAtoms(k, m) * moleFraction(k);
595 }
596 return numerator / denom;
597}
598
600{
601 return density()/meanMolecularWeight();
602}
603
604double Phase::molarVolume() const
605{
606 return 1.0/molarDensity();
607}
608
609void Phase::setDensity(const double density_)
610{
611 assertCompressible("setDensity");
612 if (density_ > 0.0) {
613 m_dens = density_;
614 } else {
615 throw CanteraError("Phase::setDensity",
616 "density must be positive. density = {}", density_);
617 }
618}
619
620void Phase::assignDensity(const double density_)
621{
622 if (density_ > 0.0) {
623 m_dens = density_;
624 } else {
625 throw CanteraError("Phase::assignDensity",
626 "density must be positive. density = {}", density_);
627 }
628}
629
631{
632 double cdens = 0.0;
633 for (size_t k = 0; k < m_kk; k++) {
634 cdens += charge(k)*moleFraction(k);
635 }
636 return cdens * Faraday;
637}
638
639double Phase::mean_X(const double* const Q) const
640{
641 return m_mmw*std::inner_product(m_ym.begin(), m_ym.end(), Q, 0.0);
642}
643
644double Phase::mean_X(const vector<double>& Q) const
645{
646 return m_mmw*std::inner_product(m_ym.begin(), m_ym.end(), Q.begin(), 0.0);
647}
648
649double Phase::sum_xlogx() const
650{
651 double sumxlogx = 0;
652 for (size_t k = 0; k < m_kk; k++) {
653 sumxlogx += m_ym[k] * std::log(std::max(m_ym[k], SmallNumber));
654 }
655 return m_mmw * sumxlogx + std::log(m_mmw);
656}
657
658size_t Phase::addElement(const string& symbol, double weight, int atomic_number,
659 double entropy298, int elem_type)
660{
661 // Look up the atomic weight if not given
662 if (weight == 0.0) {
663 try {
664 weight = getElementWeight(symbol);
665 } catch (CanteraError&) {
666 // assume this is just a custom element with zero atomic weight
667 }
668 } else if (weight == -12345.0) {
669 weight = getElementWeight(symbol);
670 }
671
672 // Try to look up the standard entropy if not given. Fail silently.
673 if (entropy298 == ENTROPY298_UNKNOWN) {
674 try {
675 const static AnyMap db = AnyMap::fromYamlFile(
676 "element-standard-entropies.yaml");
677 const AnyMap& elem = db["elements"].getMapWhere("symbol", symbol);
678 entropy298 = elem.convert("entropy298", "J/kmol/K", ENTROPY298_UNKNOWN);
679 } catch (CanteraError&) {
680 }
681 }
682
683 // Check for duplicates
684 auto iter = find(m_elementNames.begin(), m_elementNames.end(), symbol);
685 if (iter != m_elementNames.end()) {
686 size_t m = iter - m_elementNames.begin();
687 if (m_atomicWeights[m] != weight) {
688 throw CanteraError("Phase::addElement",
689 "Duplicate elements ({}) have different weights", symbol);
690 } else {
691 // Ignore attempt to add duplicate element with the same weight
692 return m;
693 }
694 }
695
696 // Add the new element
697 m_atomicWeights.push_back(weight);
698 m_elementNames.push_back(symbol);
699 m_atomicNumbers.push_back(atomic_number);
700 m_entropy298.push_back(entropy298);
701 if (symbol == "E") {
703 } else {
704 m_elem_type.push_back(elem_type);
705 }
706 m_mm++;
707
708 // Update species compositions
709 if (m_kk) {
710 vector<double> old(m_speciesComp);
711 m_speciesComp.resize(m_kk*m_mm, 0.0);
712 for (size_t k = 0; k < m_kk; k++) {
713 size_t m_old = m_mm - 1;
714 for (size_t m = 0; m < m_old; m++) {
715 m_speciesComp[k * m_mm + m] = old[k * (m_old) + m];
716 }
717 m_speciesComp[k * (m_mm) + (m_mm-1)] = 0.0;
718 }
719 }
720
721 return m_mm-1;
722}
723
724bool Phase::addSpecies(shared_ptr<Species> spec)
725{
726 if (m_nSpeciesLocks) {
727 throw CanteraError("Phase::addSpecies",
728 "Cannot add species to ThermoPhase '{}' because it is being "
729 "used by another object,\nsuch as a Reactor, Domain1D (flame), "
730 "SolutionArray, or MultiPhase (Mixture) object.", m_name);
731 }
732
733 if (m_species.find(spec->name) != m_species.end()) {
734 throw CanteraError("Phase::addSpecies",
735 "Phase '{}' already contains a species named '{}'.",
736 m_name, spec->name);
737 }
738
739 vector<double> comp(nElements());
740 for (const auto& [eName, stoich] : spec->composition) {
741 size_t m = elementIndex(eName, false);
742 if (m == npos) { // Element doesn't exist in this phase
744 case UndefElement::ignore:
745 return false;
746
747 case UndefElement::add:
748 addElement(eName);
749 comp.resize(nElements());
750 m = elementIndex(eName, true);
751 break;
752
753 case UndefElement::error:
754 default:
755 throw CanteraError("Phase::addSpecies",
756 "Species '{}' contains an undefined element '{}'.",
757 spec->name, eName);
758 }
759 }
760 comp[m] = stoich;
761 }
762
763 size_t ne = nElements();
764 const vector<double>& aw = atomicWeights();
765 if (spec->charge != 0.0) {
766 size_t eindex = elementIndex("E", false);
767 if (eindex != npos) {
768 double ecomp = comp[eindex];
769 if (fabs(spec->charge + ecomp) > 0.001) {
770 if (ecomp != 0.0) {
771 throw CanteraError("Phase::addSpecies",
772 "Input charge and element E compositions differ "
773 "for species " + spec->name);
774 } else {
775 // Just fix up the element E composition based on the input
776 // species charge
777 comp[eindex] = -spec->charge;
778 }
779 }
780 } else {
781 addElement("E", 0.000545, 0, 0.0, CT_ELEM_TYPE_ELECTRONCHARGE);
782 ne = nElements();
783 eindex = elementIndex("E", true);
784 comp.resize(ne);
785 comp[ne - 1] = - spec->charge;
786 }
787 }
788
789 double wt = 0.0;
790 for (size_t m = 0; m < ne; m++) {
791 wt += comp[m] * aw[m];
792 }
793
794 // Some surface phases may define species representing empty sites
795 // that have zero molecular weight. Give them a very small molecular
796 // weight to avoid dividing by zero.
797 wt = std::max(wt, Tiny);
798
799 spec->setMolecularWeight(wt);
800
801 m_molwts.push_back(wt);
802 m_rmolwts.push_back(1.0/wt);
803
804 for (size_t m = 0; m < ne; m++) {
805 m_speciesComp.push_back(comp[m]);
806 }
807
808 m_speciesNames.push_back(spec->name);
809 m_species[spec->name] = spec;
810 m_speciesIndices[spec->name] = m_kk;
811 m_speciesCharge.push_back(spec->charge);
812
813 string nLower = toLowerCopy(spec->name);
814 if (m_speciesLower.find(nLower) == m_speciesLower.end()) {
815 m_speciesLower[nLower] = m_kk;
816 } else {
817 m_speciesLower[nLower] = npos;
818 }
819 m_kk++;
820
821 // Ensure that the Phase has a valid mass fraction vector that sums to
822 // one. We will assume that species 0 has a mass fraction of 1.0 and mass
823 // fraction of all other species is 0.0.
824 if (m_kk == 1) {
825 m_y.push_back(1.0);
826 m_ym.push_back(m_rmolwts[0]);
827 m_mmw = 1.0 / m_ym[0];
828 } else {
829 m_y.push_back(0.0);
830 m_ym.push_back(0.0);
831 }
832 m_workS.push_back(0.0);
834 return true;
835}
836
837void Phase::modifySpecies(size_t k, shared_ptr<Species> spec)
838{
839 if (speciesName(k) != spec->name) {
840 throw CanteraError("Phase::modifySpecies",
841 "New species name '{}' does not match existing name '{}'",
842 spec->name, speciesName(k));
843 }
844 const shared_ptr<Species>& old = m_species[spec->name];
845 if (spec->composition != old->composition) {
846 throw CanteraError("Phase::modifySpecies",
847 "New composition for '{}' does not match existing composition",
848 spec->name);
849 }
850 m_species[spec->name] = spec;
852}
853
854void Phase::addSpeciesAlias(const string& name, const string& alias)
855{
856 if (speciesIndex(alias, false) != npos) {
857 throw CanteraError("Phase::addSpeciesAlias",
858 "Invalid alias '{}': species already exists", alias);
859 }
860 size_t k = speciesIndex(name, false);
861 if (k != npos) {
862 m_speciesIndices[alias] = k;
863 } else {
864 throw CanteraError("Phase::addSpeciesAlias",
865 "Unable to add alias '{}' "
866 "(original species '{}' not found).", alias, name);
867 }
868}
869
871{
872 if (!m_nSpeciesLocks) {
873 throw CanteraError("Phase::removeSpeciesLock",
874 "ThermoPhase '{}' has no current species locks.", m_name);
875 }
877}
878
879vector<string> Phase::findIsomers(const Composition& compMap) const
880{
881 vector<string> isomerNames;
882
883 for (const auto& [name, species] : m_species) {
884 if (species->composition == compMap) {
885 isomerNames.emplace_back(name);
886 }
887 }
888
889 return isomerNames;
890}
891
892vector<string> Phase::findIsomers(const string& comp) const
893{
894 return findIsomers(parseCompString(comp));
895}
896
897shared_ptr<Species> Phase::species(const string& name) const
898{
899 size_t k = speciesIndex(name, true);
900 return m_species.at(speciesName(k));
901}
902
903shared_ptr<Species> Phase::species(size_t k) const
904{
906 return m_species.at(m_speciesNames[k]);
907}
908
910 m_undefinedElementBehavior = UndefElement::ignore;
911}
912
914 m_undefinedElementBehavior = UndefElement::add;
915}
916
918 m_undefinedElementBehavior = UndefElement::error;
919}
920
921bool Phase::ready() const
922{
923 return (m_kk > 0);
924}
925
927 m_stateNum++;
928 m_cache.clear();
929}
930
931void Phase::setMolecularWeight(const int k, const double mw)
932{
933 m_molwts[k] = mw;
934 m_rmolwts[k] = 1.0/mw;
935
936 transform(m_y.begin(), m_y.end(), m_rmolwts.begin(), m_ym.begin(),
937 multiplies<double>());
938 m_mmw = 1.0 / accumulate(m_ym.begin(), m_ym.end(), 0.0);
939}
940
942 m_stateNum++;
943}
944
945vector<double> Phase::getCompositionFromMap(const Composition& comp) const
946{
947 vector<double> X(m_kk);
948 for (const auto& [name, value] : comp) {
949 size_t loc = speciesIndex(name, true);
950 X[loc] = value;
951 }
952 return X;
953}
954
955void Phase::massFractionsToMoleFractions(const double* Y, double* X) const
956{
957 double rmmw = 0.0;
958 for (size_t k = 0; k != m_kk; ++k) {
959 rmmw += Y[k]/m_molwts[k];
960 }
961 if (rmmw == 0.0) {
962 throw CanteraError("Phase::massFractionsToMoleFractions",
963 "no input composition given");
964 }
965 for (size_t k = 0; k != m_kk; ++k) {
966 X[k] = Y[k]/(rmmw*m_molwts[k]);
967 }
968}
969
970void Phase::moleFractionsToMassFractions(const double* X, double* Y) const
971{
972 double mmw = dot(X, X+m_kk, m_molwts.data());
973 if (mmw == 0.0) {
974 throw CanteraError("Phase::moleFractionsToMassFractions",
975 "no input composition given");
976 }
977 double rmmw = 1.0/mmw;
978 for (size_t k = 0; k != m_kk; ++k) {
979 Y[k] = X[k]*m_molwts[k]*rmmw;
980 }
981}
982
983} // namespace Cantera
#define CT_ELEM_TYPE_ELECTRONCHARGE
This refers to conservation of electrons.
Definition Elements.h:41
#define ENTROPY298_UNKNOWN
Number indicating we don't know the entropy of the element in its most stable state at 298....
Definition Elements.h:85
Header file for class Phase.
Declaration for class Cantera::Species.
Headers for the factory class that can create known ThermoPhase objects (see Thermodynamic Properties...
A map of string keys to values whose type can vary at runtime.
Definition AnyMap.h:431
double convert(const string &key, const string &units) const
Convert the item stored by the given key to the units specified in units.
Definition AnyMap.cpp:1595
static AnyMap fromYamlFile(const string &name, const string &parent_name="")
Create an AnyMap from a YAML file.
Definition AnyMap.cpp:1841
Array size error.
Base class for exceptions thrown by Cantera classes.
An array index is out of range.
virtual vector< string > partialStates() const
Return a vector of settable partial property sets within a phase.
Definition Phase.cpp:212
void getCharges(double *charges) const
Copy the vector of species charges into array charges.
Definition Phase.cpp:430
virtual void getConcentrations(double *const c) const
Get the species concentrations (kmol/m^3).
Definition Phase.cpp:507
map< string, size_t > m_speciesLower
Map of lower-case species names to indices.
Definition Phase.h:963
double massFraction(size_t k) const
Return the mass fraction of a single species.
Definition Phase.cpp:480
virtual double molarDensity() const
Molar density (kmol/m^3).
Definition Phase.cpp:599
void assignDensity(const double density_)
Set the internally stored constant density (kg/m^3) of the phase.
Definition Phase.cpp:620
virtual bool addSpecies(shared_ptr< Species > spec)
Add a Species to this Phase.
Definition Phase.cpp:724
virtual void setMoleFractions(const double *const x)
Set the mole fractions to the specified values.
Definition Phase.cpp:307
int changeElementType(int m, int elem_type)
Change the element type of the mth constraint Reassigns an element type.
Definition Phase.cpp:94
const vector< double > & atomicWeights() const
Return a read-only reference to the vector of atomic weights.
Definition Phase.cpp:79
virtual vector< string > fullStates() const
Return a vector containing full states defining a phase.
Definition Phase.cpp:194
void assertCompressible(const string &setter) const
Ensure that phase is compressible.
Definition Phase.h:850
vector< double > m_workS
Vector of size m_kk, used as a temporary holding area.
Definition Phase.h:914
void restoreState(const vector< double > &state)
Restore a state saved on a previous call to saveState.
Definition Phase.cpp:283
vector< double > m_speciesComp
Atomic composition of the species.
Definition Phase.h:899
ValueCache m_cache
Cached for saved calculations within each ThermoPhase.
Definition Phase.h:870
virtual void restorePartialState(size_t lenstate, const double *state)
Set the internal thermodynamic state of the phase, excluding composition.
Definition Phase.cpp:240
size_t m_nSpeciesLocks
Reference counter preventing species addition.
Definition Phase.h:905
vector< string > m_speciesNames
Vector of the species names.
Definition Phase.h:957
size_t nSpecies() const
Returns the number of species in the phase.
Definition Phase.h:245
size_t checkElementIndex(size_t m) const
Check that the specified element index is in range.
Definition Phase.cpp:35
bool m_caseSensitiveSpecies
Flag determining whether case sensitive species names are enforced.
Definition Phase.h:911
vector< string > m_elementNames
element names
Definition Phase.h:968
void ignoreUndefinedElements()
Set behavior when adding a species containing undefined elements to just skip the species.
Definition Phase.cpp:909
UndefElement::behavior m_undefinedElementBehavior
Flag determining behavior when adding species with an undefined element.
Definition Phase.h:908
virtual void setMassFractions_NoNorm(const double *const y)
Set the mass fractions to the specified values without normalizing.
Definition Phase.cpp:373
virtual map< string, size_t > nativeState() const
Return a map of properties defining the native state of a substance.
Definition Phase.cpp:164
double chargeDensity() const
Charge density [C/m^3].
Definition Phase.cpp:630
void addUndefinedElements()
Set behavior when adding a species containing undefined elements to add those elements to the phase.
Definition Phase.cpp:913
virtual void setConcentrationsNoNorm(const double *const conc)
Set the concentrations without ignoring negative concentrations.
Definition Phase.cpp:534
vector< int > m_atomicNumbers
element atomic numbers
Definition Phase.h:967
size_t m_kk
Number of species in the phase.
Definition Phase.h:890
int atomicNumber(size_t m) const
Atomic number of element m.
Definition Phase.cpp:84
virtual void modifySpecies(size_t k, shared_ptr< Species > spec)
Modify the thermodynamic data associated with a species.
Definition Phase.cpp:837
double m_mmw
mean molecular weight of the mixture (kg kmol-1)
Definition Phase.h:935
double elementalMoleFraction(const size_t m) const
Elemental mole fraction of element m.
Definition Phase.cpp:582
size_t speciesIndex(const string &name, bool raise=true) const
Returns the index of a species named 'name' within the Phase object.
Definition Phase.cpp:127
void setState_TD(double t, double rho)
Set the internally stored temperature (K) and density (kg/m^3)
Definition Phase.cpp:395
vector< double > m_rmolwts
inverse of species molecular weights (kmol kg-1)
Definition Phase.h:950
double temperature() const
Temperature (K).
Definition Phase.h:598
virtual void setPressure(double p)
Set the internally stored pressure (Pa) at constant temperature and composition.
Definition Phase.h:652
virtual bool isCompressible() const
Return whether phase represents a compressible substance.
Definition Phase.h:269
double meanMolecularWeight() const
The mean molecular weight. Units: (kg/kmol)
Definition Phase.h:691
void moleFractionsToMassFractions(const double *X, double *Y) const
Converts a mixture composition from mass fractions to mole fractions.
Definition Phase.cpp:970
virtual void setConcentrations(const double *const conc)
Set the concentrations to the specified values within the phase.
Definition Phase.cpp:512
void removeSpeciesLock()
Decrement species lock counter.
Definition Phase.cpp:870
void saveState(vector< double > &state) const
Save the current internal state of the phase.
Definition Phase.cpp:263
Composition getMoleFractionsByName(double threshold=0.0) const
Get the mole fractions by name.
Definition Phase.cpp:435
virtual double concentration(const size_t k) const
Concentration of species k.
Definition Phase.cpp:501
double atomicWeight(size_t m) const
Atomic weight of element m.
Definition Phase.cpp:69
void setMassFractionsByName(const Composition &yMap)
Set the species mass fractions by name.
Definition Phase.cpp:384
int elementType(size_t m) const
Return the element constraint type Possible types include:
Definition Phase.cpp:89
string speciesName(size_t k) const
Name of the species with index k.
Definition Phase.cpp:143
map< string, size_t > m_speciesIndices
Map of species names to indices.
Definition Phase.h:960
virtual void setDensity(const double density_)
Set the internally stored density (kg/m^3) of the phase.
Definition Phase.cpp:609
Composition getMassFractionsByName(double threshold=0.0) const
Get the mass fractions by name.
Definition Phase.cpp:447
virtual size_t stateSize() const
Return size of vector defining internal state of the phase.
Definition Phase.cpp:255
string nativeMode() const
Return string acronym representing the native state of a Phase.
Definition Phase.cpp:181
vector< double > getCompositionFromMap(const Composition &comp) const
Converts a Composition to a vector with entries for each species Species that are not specified are s...
Definition Phase.cpp:945
map< string, shared_ptr< Species > > m_species
Map of Species objects.
Definition Phase.h:903
size_t findSpeciesLower(const string &nameStr) const
Find lowercase species name in m_speciesIndices when case sensitive species names are not enforced an...
Definition Phase.cpp:108
vector< double > m_molwts
species molecular weights (kg kmol-1)
Definition Phase.h:948
virtual vector< string > findIsomers(const Composition &compMap) const
Return a vector with isomers names matching a given composition map.
Definition Phase.cpp:879
const vector< double > & inverseMolecularWeights() const
Return a const reference to the internal vector of molecular weights.
Definition Phase.cpp:425
virtual bool isPure() const
Return whether phase represents a pure (single species) substance.
Definition Phase.h:259
vector< double > m_y
Mass fractions of the species.
Definition Phase.h:946
void getMoleFractions(double *const x) const
Get the species mole fraction vector.
Definition Phase.cpp:459
void setMoleFractionsByName(const Composition &xMap)
Set the species mole fractions by name.
Definition Phase.cpp:348
const double * massFractions() const
Return a const pointer to the mass fraction array.
Definition Phase.h:478
vector< int > m_elem_type
Vector of element types.
Definition Phase.h:969
double sum_xlogx() const
Evaluate .
Definition Phase.cpp:649
string m_name
Name of the phase.
Definition Phase.h:925
const vector< double > & molecularWeights() const
Return a const reference to the internal vector of molecular weights.
Definition Phase.cpp:420
double moleFraction(size_t k) const
Return the mole fraction of a single species.
Definition Phase.cpp:464
double m_dens
Density (kg m-3).
Definition Phase.h:933
const vector< string > & elementNames() const
Return a read-only reference to the vector of element names.
Definition Phase.cpp:64
virtual double density() const
Density (kg/m^3).
Definition Phase.h:623
virtual void compositionChanged()
Apply changes to the state which are needed after the composition changes.
Definition Phase.cpp:941
vector< double > m_atomicWeights
element atomic weights (kg kmol-1)
Definition Phase.h:966
void getMolecularWeights(double *weights) const
Copy the vector of molecular weights into array weights.
Definition Phase.cpp:414
double nAtoms(size_t k, size_t m) const
Number of atoms of element m in species k.
Definition Phase.cpp:101
void addSpeciesAlias(const string &name, const string &alias)
Add a species alias (that is, a user-defined alternative species name).
Definition Phase.cpp:854
virtual void setMolesNoTruncate(const double *const N)
Set the state of the object with moles in [kmol].
Definition Phase.cpp:553
size_t checkSpeciesIndex(size_t k) const
Check that the specified species index is in range.
Definition Phase.cpp:156
virtual void setTemperature(double temp)
Set the internally stored temperature of the phase (K).
Definition Phase.h:659
size_t nElements() const
Number of elements.
Definition Phase.cpp:30
void setMolecularWeight(const int k, const double mw)
Set the molecular weight of a single species to a given value.
Definition Phase.cpp:931
double mean_X(const double *const Q) const
Evaluate the mole-fraction-weighted mean of an array Q.
Definition Phase.cpp:639
vector< double > m_entropy298
Entropy at 298.15 K and 1 bar of stable state pure elements (J kmol-1)
Definition Phase.h:972
virtual void savePartialState(size_t lenstate, double *state) const
Save the current thermodynamic state of the phase, excluding composition.
Definition Phase.cpp:225
vector< double > m_ym
m_ym[k] = mole fraction of species k divided by the mean molecular weight of mixture.
Definition Phase.h:939
virtual void setMassFractions(const double *const y)
Set the mass fractions to the specified values and normalize them.
Definition Phase.cpp:359
const vector< string > & speciesNames() const
Return a const reference to the vector of species names.
Definition Phase.cpp:151
size_t elementIndex(const string &name, bool raise=true) const
Return the index of element named 'name'.
Definition Phase.cpp:51
virtual bool ready() const
Returns a bool indicating whether the object is ready for use.
Definition Phase.cpp:921
double molecularWeight(size_t k) const
Molecular weight of species k.
Definition Phase.cpp:408
double elementalMassFraction(const size_t m) const
Elemental mass fraction of element m.
Definition Phase.cpp:572
shared_ptr< Species > species(const string &name) const
Return the Species object for the named species.
Definition Phase.cpp:897
virtual double molarVolume() const
Molar volume (m^3/kmol).
Definition Phase.cpp:604
virtual void invalidateCache()
Invalidate any cached values which are normally updated only when a change in state is detected.
Definition Phase.cpp:926
void getMassFractions(double *const y) const
Get the species mass fractions.
Definition Phase.cpp:496
virtual size_t partialStateSize() const
Get the size of the partial state vector of the phase.
Definition Phase.h:316
int m_stateNum
State Change variable.
Definition Phase.h:954
void throwUndefinedElements()
Set the behavior when adding a species containing undefined elements to throw an exception.
Definition Phase.cpp:917
void setName(const string &nm)
Sets the string name for the phase.
Definition Phase.cpp:25
size_t m_mm
Number of elements.
Definition Phase.h:965
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
double charge(size_t k) const
Dimensionless electrical charge of a single molecule of species k The charge is normalized by the the...
Definition Phase.h:574
void massFractionsToMoleFractions(const double *Y, double *X) const
Converts a mixture composition from mole fractions to mass fractions.
Definition Phase.cpp:955
double entropyElement298(size_t m) const
Entropy of the element in its standard state at 298 K and 1 bar.
Definition Phase.cpp:74
virtual void setMoleFractions_NoNorm(const double *const x)
Set the mole fractions to the specified values without normalizing.
Definition Phase.cpp:339
vector< double > m_speciesCharge
Vector of species charges.
Definition Phase.h:901
size_t addElement(const string &symbol, double weight=-12345.0, int atomicNumber=0, double entropy298=ENTROPY298_UNKNOWN, int elem_type=CT_ELEM_TYPE_ABSPOS)
Add an element.
Definition Phase.cpp:658
string name() const
Return the name of the phase.
Definition Phase.cpp:20
void clear()
Clear all cached values.
string toLowerCopy(const string &input)
Convert to lower case.
Composition parseCompString(const string &ss, const vector< string > &names)
Parse a composition string into a map consisting of individual key:composition pairs.
double dot(InputIter x_begin, InputIter x_end, InputIter2 y_begin)
Function that calculates a templated inner product.
Definition utilities.h:82
void scale(InputIter begin, InputIter end, OutputIter out, S scale_factor)
Multiply elements of an array by a scale factor.
Definition utilities.h:104
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
double getElementWeight(const string &ename)
Get the atomic weight of an element.
Definition Elements.cpp:251
const double Tiny
Small number to compare differences of mole fractions against.
Definition ct_defs.h:173
const double SmallNumber
smallest number to compare to zero.
Definition ct_defs.h:158
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...