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