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