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