Cantera  2.2.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
MultiPhase.cpp
Go to the documentation of this file.
1 /**
2  * @file MultiPhase.cpp
3  * Definitions for the \link Cantera::MultiPhase MultiPhase\endlink
4  * object that is used to set up multiphase equilibrium problems (see \ref equilfunctions).
5  */
6 
12 
13 using namespace std;
14 
15 namespace Cantera
16 {
17 
18 MultiPhase::MultiPhase() :
19  m_np(0),
20  m_temp(298.15),
21  m_press(OneBar),
22  m_nel(0),
23  m_nsp(0),
24  m_init(false),
25  m_eloc(npos),
26  m_Tmin(1.0),
27  m_Tmax(100000.0)
28 {
29 }
30 
31 MultiPhase::MultiPhase(const MultiPhase& right) :
32  m_np(0),
33  m_temp(298.15),
34  m_press(OneBar),
35  m_nel(0),
36  m_nsp(0),
37  m_init(false),
38  m_eloc(npos),
39  m_Tmin(1.0),
40  m_Tmax(100000.0)
41 {
42  operator=(right);
43 }
44 
45 MultiPhase& MultiPhase::operator=(const MultiPhase& right)
46 {
47  if (&right != this) {
48  m_moles = right.m_moles;
49  // shallow copy of phase pointers
50  m_phase = right.m_phase;
51  m_atoms = right.m_atoms;
52  m_moleFractions = right.m_moleFractions;
53  m_spphase = right.m_spphase;
54  m_spstart = right.m_spstart;
55  m_enames = right.m_enames;
56  m_enamemap = right.m_enamemap;
57  m_np = right.m_np;
58  m_temp = right.m_temp;
59  m_press = right.m_press;
60  m_nel = right.m_nel;
61  m_nsp = right.m_nsp;
62  m_init = right.m_init;
63  m_eloc = right.m_eloc;
64  m_temp_OK = right.m_temp_OK;
65  m_Tmin = right.m_Tmin;
66  m_Tmax = right.m_Tmax;
67  m_elemAbundances = right.m_elemAbundances;
68  }
69  return *this;
70 }
71 
73 {
74  size_t n;
75  for (n = 0; n < mix.m_np; n++) {
76  addPhase(mix.m_phase[n], mix.m_moles[n]);
77  }
78 }
79 
80 void MultiPhase::addPhases(std::vector<ThermoPhase*>& phases,
81  const vector_fp& phaseMoles)
82 {
83  size_t np = phases.size();
84  size_t n;
85  for (n = 0; n < np; n++) {
86  addPhase(phases[n], phaseMoles[n]);
87  }
88  init();
89 }
90 
91 void MultiPhase::addPhase(ThermoPhase* p, doublereal moles)
92 {
93  if (m_init) {
94  throw CanteraError("addPhase",
95  "phases cannot be added after init() has been called.");
96  }
97 
98  // save the pointer to the phase object
99  m_phase.push_back(p);
100 
101  // store its number of moles
102  m_moles.push_back(moles);
103  m_temp_OK.push_back(true);
104 
105  // update the number of phases and the total number of
106  // species
107  m_np = m_phase.size();
108  m_nsp += p->nSpecies();
109 
110  // determine if this phase has new elements
111  // for each new element, add an entry in the map
112  // from names to index number + 1:
113 
114  string ename;
115  // iterate over the elements in this phase
116  size_t m, nel = p->nElements();
117  for (m = 0; m < nel; m++) {
118  ename = p->elementName(m);
119 
120  // if no entry is found for this element name, then
121  // it is a new element. In this case, add the name
122  // to the list of names, increment the element count,
123  // and add an entry to the name->(index+1) map.
124  if (m_enamemap.find(ename) == m_enamemap.end()) {
125  m_enamemap[ename] = m_nel + 1;
126  m_enames.push_back(ename);
127  m_atomicNumber.push_back(p->atomicNumber(m));
128 
129  // Element 'E' (or 'e') is special. Note its location.
130  if (ename == "E" || ename == "e") {
131  m_eloc = m_nel;
132  }
133 
134  m_nel++;
135  }
136  }
137 
138  // If the mixture temperature hasn't been set, then set the
139  // temperature and pressure to the values for the phase being
140  // added. There is no good way to do this. However, this will be overridden later.
141  if (m_temp == 298.15 && p->temperature() > 2.0E-3) {
142  m_temp = p->temperature();
143  m_press = p->pressure();
144  }
145 
146  // If this is a solution phase, update the minimum and maximum
147  // mixture temperatures. Stoichiometric phases are excluded,
148  // since a mixture may define multiple stoichiometric phases,
149  // each of which has thermo data valid only over a limited
150  // range. For example, a mixture might be defined to contain a
151  // phase representing water ice and one representing liquid
152  // water, only one of which should be present if the mixture
153  // represents an equilibrium state.
154  if (p->nSpecies() > 1) {
155  m_Tmin = std::max(p->minTemp(), m_Tmin);
156  m_Tmax = std::min(p->maxTemp(), m_Tmax);
157  }
158 }
159 
161 {
162  if (m_init) {
163  return;
164  }
165  size_t ip, kp, k = 0, nsp, m;
166  size_t mlocal;
167  string sym;
168 
169  // allocate space for the atomic composition matrix
170  m_atoms.resize(m_nel, m_nsp, 0.0);
171  m_moleFractions.resize(m_nsp, 0.0);
172  m_elemAbundances.resize(m_nel, 0.0);
173 
174  // iterate over the elements
175  // -> fill in m_atoms(m,k), m_snames(k), m_spphase(k),
176  // m_sptart(ip)
177  for (m = 0; m < m_nel; m++) {
178  sym = m_enames[m];
179  k = 0;
180  // iterate over the phases
181  for (ip = 0; ip < m_np; ip++) {
182  ThermoPhase* p = m_phase[ip];
183  nsp = p->nSpecies();
184  mlocal = p->elementIndex(sym);
185  for (kp = 0; kp < nsp; kp++) {
186  if (mlocal != npos) {
187  m_atoms(m, k) = p->nAtoms(kp, mlocal);
188  }
189  if (m == 0) {
190  m_snames.push_back(p->speciesName(kp));
191  if (kp == 0) {
192  m_spstart.push_back(m_spphase.size());
193  }
194  m_spphase.push_back(ip);
195  }
196  k++;
197  }
198  }
199  }
200 
201  if (m_eloc != npos) {
202  doublereal esum;
203  for (k = 0; k < m_nsp; k++) {
204  esum = 0.0;
205  for (m = 0; m < m_nel; m++) {
206  if (m != m_eloc) {
207  esum += m_atoms(m,k) * m_atomicNumber[m];
208  }
209  }
210  }
211  }
212 
213  /// set the initial composition within each phase to the
214  /// mole fractions stored in the phase objects
215  m_init = true;
216 
218 
219  updatePhases();
220 }
221 
223 {
224  if (!m_init) {
225  init();
226  }
227  m_phase[n]->setTemperature(m_temp);
228  m_phase[n]->setMoleFractions_NoNorm(DATA_PTR(m_moleFractions) + m_spstart[n]);
229  m_phase[n]->setPressure(m_press);
230  return *m_phase[n];
231 }
232 
233 void MultiPhase::checkPhaseIndex(size_t m) const
234 {
235  if (m >= nPhases()) {
236  throw IndexError("checkPhaseIndex", "phase", m, nPhases()-1);
237  }
238 }
239 
240 void MultiPhase::checkPhaseArraySize(size_t mm) const
241 {
242  if (nPhases() > mm) {
243  throw ArraySizeError("checkPhaseIndex", mm, nPhases());
244  }
245 }
246 
247 doublereal MultiPhase::speciesMoles(size_t k) const
248 {
249  size_t ip = m_spphase[k];
250  return m_moles[ip]*m_moleFractions[k];
251 }
252 
253 doublereal MultiPhase::elementMoles(size_t m) const
254 {
255  doublereal sum = 0.0, phasesum;
256  size_t i, k = 0, ik, nsp;
257  for (i = 0; i < m_np; i++) {
258  phasesum = 0.0;
259  nsp = m_phase[i]->nSpecies();
260  for (ik = 0; ik < nsp; ik++) {
261  k = speciesIndex(ik, i);
262  phasesum += m_atoms(m,k)*m_moleFractions[k];
263  }
264  sum += phasesum * m_moles[i];
265  }
266  return sum;
267 }
268 
269 doublereal MultiPhase::charge() const
270 {
271  doublereal sum = 0.0;
272  size_t i;
273  for (i = 0; i < m_np; i++) {
274  sum += phaseCharge(i);
275  }
276  return sum;
277 }
278 
279 size_t MultiPhase::speciesIndex(const std::string& speciesName, const std::string& phaseName)
280 {
281  if (!m_init) {
282  init();
283  }
284  size_t p = phaseIndex(phaseName);
285  if (p == npos) {
286  throw CanteraError("MultiPhase::speciesIndex", "phase not found: " + phaseName);
287  }
288  size_t k = m_phase[p]->speciesIndex(speciesName);
289  if (k == npos) {
290  throw CanteraError("MultiPhase::speciesIndex", "species not found: " + speciesName);
291  }
292  return m_spstart[p] + k;
293 }
294 
295 doublereal MultiPhase::phaseCharge(size_t p) const
296 {
297  doublereal phasesum = 0.0;
298  size_t ik, k, nsp = m_phase[p]->nSpecies();
299  for (ik = 0; ik < nsp; ik++) {
300  k = speciesIndex(ik, p);
301  phasesum += m_phase[p]->charge(ik)*m_moleFractions[k];
302  }
303  return Faraday*phasesum*m_moles[p];
304 }
305 
306 void MultiPhase::getChemPotentials(doublereal* mu) const
307 {
308  size_t i, loc = 0;
309  updatePhases();
310  for (i = 0; i < m_np; i++) {
311  m_phase[i]->getChemPotentials(mu + loc);
312  loc += m_phase[i]->nSpecies();
313  }
314 }
315 
316 void MultiPhase::getValidChemPotentials(doublereal not_mu,
317  doublereal* mu, bool standard) const
318 {
319  size_t i, loc = 0;
320 
321  updatePhases();
322  // iterate over the phases
323  for (i = 0; i < m_np; i++) {
324  if (tempOK(i) || m_phase[i]->nSpecies() > 1) {
325  if (!standard) {
326  m_phase[i]->getChemPotentials(mu + loc);
327  } else {
328  m_phase[i]->getStandardChemPotentials(mu + loc);
329  }
330  } else {
331  fill(mu + loc, mu + loc + m_phase[i]->nSpecies(), not_mu);
332  }
333  loc += m_phase[i]->nSpecies();
334  }
335 }
336 
337 bool MultiPhase::solutionSpecies(size_t k) const
338 {
339  if (m_phase[m_spphase[k]]->nSpecies() > 1) {
340  return true;
341  } else {
342  return false;
343  }
344 }
345 
346 doublereal MultiPhase::gibbs() const
347 {
348  size_t i;
349  doublereal sum = 0.0;
350  updatePhases();
351  for (i = 0; i < m_np; i++) {
352  if (m_moles[i] > 0.0) {
353  sum += m_phase[i]->gibbs_mole() * m_moles[i];
354  }
355  }
356  return sum;
357 }
358 
359 doublereal MultiPhase::enthalpy() const
360 {
361  size_t i;
362  doublereal sum = 0.0;
363  updatePhases();
364  for (i = 0; i < m_np; i++) {
365  if (m_moles[i] > 0.0) {
366  sum += m_phase[i]->enthalpy_mole() * m_moles[i];
367  }
368  }
369  return sum;
370 }
371 
372 doublereal MultiPhase::IntEnergy() const
373 {
374  size_t i;
375  doublereal sum = 0.0;
376  updatePhases();
377  for (i = 0; i < m_np; i++) {
378  if (m_moles[i] > 0.0) {
379  sum += m_phase[i]->intEnergy_mole() * m_moles[i];
380  }
381  }
382  return sum;
383 }
384 
385 doublereal MultiPhase::entropy() const
386 {
387  size_t i;
388  doublereal sum = 0.0;
389  updatePhases();
390  for (i = 0; i < m_np; i++) {
391  if (m_moles[i] > 0.0) {
392  sum += m_phase[i]->entropy_mole() * m_moles[i];
393  }
394  }
395  return sum;
396 }
397 
398 doublereal MultiPhase::cp() const
399 {
400  size_t i;
401  doublereal sum = 0.0;
402  updatePhases();
403  for (i = 0; i < m_np; i++) {
404  if (m_moles[i] > 0.0) {
405  sum += m_phase[i]->cp_mole() * m_moles[i];
406  }
407  }
408  return sum;
409 }
410 
411 void MultiPhase::setPhaseMoleFractions(const size_t n, const doublereal* const x)
412 {
413  if (!m_init) {
414  init();
415  }
416  ThermoPhase* p = m_phase[n];
417  p->setState_TPX(m_temp, m_press, x);
418  size_t istart = m_spstart[n];
419  for (size_t k = 0; k < p->nSpecies(); k++) {
420  m_moleFractions[istart+k] = x[k];
421  }
422 }
423 
425 {
426  size_t kk = nSpecies();
427  vector_fp moles(kk, 0.0);
428  for (size_t k = 0; k < kk; k++) {
429  moles[k] = std::max(getValue(xMap, speciesName(k), 0.0), 0.0);
430  }
431  setMoles(DATA_PTR(moles));
432 }
433 
434 void MultiPhase::setMolesByName(const std::string& x)
435 {
436  // build the composition map from the string, and then set the moles.
438  setMolesByName(xx);
439 }
440 
441 void MultiPhase::getMoles(doublereal* molNum) const
442 {
443  /*
444  * First copy in the mole fractions
445  */
446  copy(m_moleFractions.begin(), m_moleFractions.end(), molNum);
447  size_t ik;
448  doublereal* dtmp = molNum;
449  for (size_t ip = 0; ip < m_np; ip++) {
450  doublereal phasemoles = m_moles[ip];
451  ThermoPhase* p = m_phase[ip];
452  size_t nsp = p->nSpecies();
453  for (ik = 0; ik < nsp; ik++) {
454  *(dtmp++) *= phasemoles;
455  }
456  }
457 }
458 
459 void MultiPhase::setMoles(const doublereal* n)
460 {
461  if (!m_init) {
462  init();
463  }
464  size_t ip, loc = 0;
465  size_t ik, k = 0, nsp;
466  doublereal phasemoles;
467  for (ip = 0; ip < m_np; ip++) {
468  ThermoPhase* p = m_phase[ip];
469  nsp = p->nSpecies();
470  phasemoles = 0.0;
471  for (ik = 0; ik < nsp; ik++) {
472  phasemoles += n[k];
473  k++;
474  }
475  m_moles[ip] = phasemoles;
476  if (nsp > 1) {
477  if (phasemoles > 0.0) {
478  p->setState_TPX(m_temp, m_press, n + loc);
480  } else {
482  }
483  } else {
484  m_moleFractions[loc] = 1.0;
485  }
486  loc += nsp;
487  }
488 }
489 
490 void MultiPhase::addSpeciesMoles(const int indexS, const doublereal addedMoles)
491 {
492  vector_fp tmpMoles(m_nsp, 0.0);
493  getMoles(DATA_PTR(tmpMoles));
494  tmpMoles[indexS] += addedMoles;
495  tmpMoles[indexS] = std::max(tmpMoles[indexS], 0.0);
496  setMoles(DATA_PTR(tmpMoles));
497 }
498 
499 void MultiPhase::setState_TP(const doublereal T, const doublereal Pres)
500 {
501  if (!m_init) {
502  init();
503  }
504  m_temp = T;
505  m_press = Pres;
506  updatePhases();
507 }
508 
509 void MultiPhase::setState_TPMoles(const doublereal T, const doublereal Pres,
510  const doublereal* n)
511 {
512  m_temp = T;
513  m_press = Pres;
514  setMoles(n);
515 }
516 
517 void MultiPhase::getElemAbundances(doublereal* elemAbundances) const
518 {
519  size_t eGlobal;
521  for (eGlobal = 0; eGlobal < m_nel; eGlobal++) {
522  elemAbundances[eGlobal] = m_elemAbundances[eGlobal];
523  }
524 }
525 
527 {
528  size_t loc = 0;
529  size_t eGlobal;
530  size_t ik, kGlobal;
531  doublereal spMoles;
532  for (eGlobal = 0; eGlobal < m_nel; eGlobal++) {
533  m_elemAbundances[eGlobal] = 0.0;
534  }
535  for (size_t ip = 0; ip < m_np; ip++) {
536  ThermoPhase* p = m_phase[ip];
537  size_t nspPhase = p->nSpecies();
538  doublereal phasemoles = m_moles[ip];
539  for (ik = 0; ik < nspPhase; ik++) {
540  kGlobal = loc + ik;
541  spMoles = m_moleFractions[kGlobal] * phasemoles;
542  for (eGlobal = 0; eGlobal < m_nel; eGlobal++) {
543  m_elemAbundances[eGlobal] += m_atoms(eGlobal, kGlobal) * spMoles;
544  }
545  }
546  loc += nspPhase;
547  }
548 }
549 
550 doublereal MultiPhase::volume() const
551 {
552  int i;
553  doublereal sum = 0;
554  for (i = 0; i < int(m_np); i++) {
555  double vol = 1.0/m_phase[i]->molarDensity();
556  sum += m_moles[i] * vol;
557  }
558  return sum;
559 }
560 
561 double MultiPhase::equilibrate(int XY, doublereal err, int maxsteps,
562  int maxiter, int loglevel)
563 {
564  warn_deprecated("MultiPhase::equilibrate(int XY, ...)",
565  "Use MultiPhase::equilibrate(string XY, ...) instead. To be removed "
566  "after Cantera 2.2.");
567  return equilibrate_MultiPhaseEquil(XY, err, maxsteps, maxiter, loglevel);
568 }
569 
570 double MultiPhase::equilibrate_MultiPhaseEquil(int XY, doublereal err,
571  int maxsteps, int maxiter,
572  int loglevel)
573 {
574  bool strt = false;
575  doublereal dt;
576  doublereal h0;
577  int n;
578  doublereal hnow, herr = 1.0;
579  doublereal snow, s0;
580  doublereal Tlow = -1.0, Thigh = -1.0;
581  doublereal Hlow = Undef, Hhigh = Undef, tnew;
582  doublereal dta=0.0, dtmax, cpb;
583  if (!m_init) {
584  init();
585  }
586 
587  if (XY == TP) {
588  // create an equilibrium manager
589  MultiPhaseEquil e(this);
590  try {
591  e.equilibrate(XY, err, maxsteps, loglevel);
592  } catch (CanteraError& err) {
593  err.save();
594  throw err;
595  }
596  return err;
597  }
598 
599  else if (XY == HP) {
600  h0 = enthalpy();
601  Tlow = 0.5*m_Tmin; // lower bound on T
602  Thigh = 2.0*m_Tmax; // upper bound on T
603  for (n = 0; n < maxiter; n++) {
604 
605  // if 'strt' is false, the current composition will be used as
606  // the starting estimate; otherwise it will be estimated
607  MultiPhaseEquil e(this, strt);
608  // start with a loose error tolerance, but tighten it as we get
609  // close to the final temperature
610 
611  try {
612  e.equilibrate(TP, err, maxsteps, loglevel);
613  hnow = enthalpy();
614  // the equilibrium enthalpy monotonically increases with T;
615  // if the current value is below the target, the we know the
616  // current temperature is too low. Set
617  if (hnow < h0) {
618  if (m_temp > Tlow) {
619  Tlow = m_temp;
620  Hlow = hnow;
621  }
622  }
623  // the current enthalpy is greater than the target; therefore the
624  // current temperature is too high.
625  else {
626  if (m_temp < Thigh) {
627  Thigh = m_temp;
628  Hhigh = hnow;
629  }
630  }
631  if (Hlow != Undef && Hhigh != Undef) {
632  cpb = (Hhigh - Hlow)/(Thigh - Tlow);
633  dt = (h0 - hnow)/cpb;
634  dta = fabs(dt);
635  dtmax = 0.5*fabs(Thigh - Tlow);
636  if (dta > dtmax) {
637  dt *= dtmax/dta;
638  }
639  } else {
640  tnew = sqrt(Tlow*Thigh);
641  dt = tnew - m_temp;
642  }
643 
644  herr = fabs((h0 - hnow)/h0);
645 
646  if (herr < err) {
647  return err;
648  }
649  tnew = m_temp + dt;
650  if (tnew < 0.0) {
651  tnew = 0.5*m_temp;
652  }
653  setTemperature(tnew);
654 
655  // if the size of Delta T is not too large, use
656  // the current composition as the starting estimate
657  if (dta < 100.0) {
658  strt = false;
659  }
660 
661  }
662 
663  catch (CanteraError& err) {
664  err.save();
665  if (!strt) {
666  strt = true;
667  } else {
668  tnew = 0.5*(m_temp + Thigh);
669  if (fabs(tnew - m_temp) < 1.0) {
670  tnew = m_temp + 1.0;
671  }
672  setTemperature(tnew);
673  }
674  }
675  }
676  throw CanteraError("MultiPhase::equilibrate_MultiPhaseEquil",
677  "No convergence for T");
678  } else if (XY == SP) {
679  s0 = entropy();
680  Tlow = 1.0; // lower bound on T
681  Thigh = 1.0e6; // upper bound on T
682  for (n = 0; n < maxiter; n++) {
683  MultiPhaseEquil e(this, strt);
684 
685  try {
686  e.equilibrate(TP, err, maxsteps, loglevel);
687  snow = entropy();
688  if (snow < s0) {
689  Tlow = std::max(Tlow, m_temp);
690  } else {
691  Thigh = std::min(Thigh, m_temp);
692  }
693  dt = (s0 - snow)*m_temp/cp();
694  dtmax = 0.5*fabs(Thigh - Tlow);
695  dtmax = (dtmax > 500.0 ? 500.0 : dtmax);
696  dta = fabs(dt);
697  if (dta > dtmax) {
698  dt *= dtmax/dta;
699  }
700  if (herr < err || dta < 1.0e-4) {
701  return err;
702  }
703  tnew = m_temp + dt;
704  setTemperature(tnew);
705 
706  // if the size of Delta T is not too large, use
707  // the current composition as the starting estimate
708  if (dta < 100.0) {
709  strt = false;
710  }
711  }
712 
713  catch (CanteraError& err) {
714  err.save();
715  if (!strt) {
716  strt = true;
717  } else {
718  tnew = 0.5*(m_temp + Thigh);
719  setTemperature(tnew);
720  }
721  }
722  }
723  throw CanteraError("MultiPhase::equilibrate_MultiPhaseEquil",
724  "No convergence for T");
725  } else if (XY == TV) {
726  doublereal v0 = volume();
727  doublereal dVdP;
728  int n;
729  bool start = true;
730  doublereal vnow, pnow, verr;
731  for (n = 0; n < maxiter; n++) {
732  pnow = pressure();
733  MultiPhaseEquil e(this, start);
734  start = false;
735 
736  e.equilibrate(TP, err, maxsteps, loglevel);
737  vnow = volume();
738  verr = fabs((v0 - vnow)/v0);
739 
740  if (verr < err) {
741  return err;
742  }
743  // find dV/dP
744  setPressure(pnow*1.01);
745  dVdP = (volume() - vnow)/(0.01*pnow);
746  setPressure(pnow + 0.5*(v0 - vnow)/dVdP);
747  }
748  }
749 
750  else {
751  throw CanteraError("MultiPhase::equilibrate_MultiPhaseEquil",
752  "unknown option");
753  }
754  return -1.0;
755 }
756 
757 void MultiPhase::equilibrate(const std::string& XY, const std::string& solver,
758  double rtol, int max_steps, int max_iter,
759  int estimate_equil, int log_level)
760 {
761  // Save the initial state so that it can be restored in case one of the
762  // solvers fails
763  vector_fp initial_moleFractions = m_moleFractions;
764  vector_fp initial_moles = m_moles;
765  double initial_T = m_temp;
766  double initial_P = m_press;
767 
768  int ixy = _equilflag(XY.c_str());
769  if (solver == "auto" || solver == "vcs") {
770  try {
771  writelog("Trying VCS equilibrium solver\n", log_level);
772  vcs_MultiPhaseEquil eqsolve(this, log_level-1);
773  int ret = eqsolve.equilibrate(ixy, estimate_equil, log_level-1,
774  rtol, max_steps);
775  if (ret) {
776  throw CanteraError("MultiPhase::equilibrate",
777  "VCS solver failed. Return code: " + int2str(ret));
778  }
779  writelog("VCS solver succeeded\n", log_level);
780  return;
781  } catch (std::exception& err) {
782  writelog("VCS solver failed.\n", log_level);
783  writelog(err.what(), log_level);
784  m_moleFractions = initial_moleFractions;
785  m_moles = initial_moles;
786  m_temp = initial_T;
787  m_press = initial_P;
788  updatePhases();
789  if (solver == "auto") {
790  } else {
791  throw;
792  }
793  }
794  }
795 
796  if (solver == "auto" || solver == "gibbs") {
797  try {
798  writelog("Trying MultiPhaseEquil (Gibbs) equilibrium solver\n",
799  log_level);
800  equilibrate_MultiPhaseEquil(ixy, rtol, max_steps, max_iter,
801  log_level-1);
802  writelog("MultiPhaseEquil solver succeeded\n", log_level);
803  return;
804  } catch (std::exception& err) {
805  writelog("MultiPhaseEquil solver failed.\n", log_level);
806  writelog(err.what(), log_level);
807  m_moleFractions = initial_moleFractions;
808  m_moles = initial_moles;
809  m_temp = initial_T;
810  m_press = initial_P;
811  updatePhases();
812  throw;
813  }
814  }
815 
816  if (solver != "auto") {
817  throw CanteraError("MultiPhase::equilibrate",
818  "Invalid solver specified: '" + solver + "'");
819  }
820 }
821 
822 #ifdef MULTIPHASE_DEVEL
823 void importFromXML(string infile, string id)
824 {
825  XML_Node* root = get_XML_File(infile);
826  if (id == "-") {
827  id = "";
828  }
829  XML_Node* x = get_XML_Node(string("#")+id, root);
830  if (x.name() != "multiphase")
831  throw CanteraError("MultiPhase::importFromXML",
832  "Current XML_Node is not a multiphase element.");
833  vector<XML_Node*> phases = x.getChildren("phase");
834  int np = phases.size();
835  int n;
836  ThermoPhase* p;
837  for (n = 0; n < np; n++) {
838  XML_Node& ph = *phases[n];
839  srcfile = infile;
840  if (ph.hasAttrib("src")) {
841  srcfile = ph["src"];
842  }
843  idstr = ph["id"];
844  p = newPhase(srcfile, idstr);
845  if (p) {
846  addPhase(p, ph.value());
847  }
848  }
849 }
850 #endif
851 
852 void MultiPhase::setTemperature(const doublereal T)
853 {
854  if (!m_init) {
855  init();
856  }
857  m_temp = T;
858  updatePhases();
859 }
860 
861 void MultiPhase::checkElementIndex(size_t m) const
862 {
863  if (m >= m_nel) {
864  throw IndexError("checkElementIndex", "elements", m, m_nel-1);
865  }
866 }
867 
869 {
870  if (m_nel > mm) {
871  throw ArraySizeError("checkElementArraySize", mm, m_nel);
872  }
873 }
874 
875 std::string MultiPhase::elementName(size_t m) const
876 {
877  return m_enames[m];
878 }
879 
880 size_t MultiPhase::elementIndex(const std::string& name) const
881 {
882  for (size_t e = 0; e < m_nel; e++) {
883  if (m_enames[e] == name) {
884  return e;
885  }
886  }
887  return npos;
888 }
889 
890 void MultiPhase::checkSpeciesIndex(size_t k) const
891 {
892  if (k >= m_nsp) {
893  throw IndexError("checkSpeciesIndex", "species", k, m_nsp-1);
894  }
895 }
896 
898 {
899  if (m_nsp > kk) {
900  throw ArraySizeError("checkSpeciesArraySize", kk, m_nsp);
901  }
902 }
903 
904 std::string MultiPhase::speciesName(const size_t k) const
905 {
906  return m_snames[k];
907 }
908 
909 doublereal MultiPhase::nAtoms(const size_t kGlob, const size_t mGlob) const
910 {
911  return m_atoms(mGlob, kGlob);
912 }
913 
914 void MultiPhase::getMoleFractions(doublereal* const x) const
915 {
916  std::copy(m_moleFractions.begin(), m_moleFractions.end(), x);
917 }
918 
919 std::string MultiPhase::phaseName(const size_t iph) const
920 {
921  const ThermoPhase* tptr = m_phase[iph];
922  return tptr->id();
923 }
924 
925 int MultiPhase::phaseIndex(const std::string& pName) const
926 {
927  std::string tmp;
928  for (int iph = 0; iph < (int) m_np; iph++) {
929  const ThermoPhase* tptr = m_phase[iph];
930  tmp = tptr->id();
931  if (tmp == pName) {
932  return iph;
933  }
934  }
935  return -1;
936 }
937 
938 doublereal MultiPhase::phaseMoles(const size_t n) const
939 {
940  return m_moles[n];
941 }
942 
943 void MultiPhase::setPhaseMoles(const size_t n, const doublereal moles)
944 {
945  m_moles[n] = moles;
946 }
947 
948 size_t MultiPhase::speciesPhaseIndex(const size_t kGlob) const
949 {
950  return m_spphase[kGlob];
951 }
952 
953 doublereal MultiPhase::moleFraction(const size_t kGlob) const
954 {
955  return m_moleFractions[kGlob];
956 }
957 
958 bool MultiPhase::tempOK(const size_t p) const
959 {
960  return m_temp_OK[p];
961 }
962 
964 {
965  size_t ip, loc = 0;
966  for (ip = 0; ip < m_np; ip++) {
967  ThermoPhase* p = m_phase[ip];
969  loc += p->nSpecies();
970  }
972 }
973 
975 {
976  size_t p, nsp, loc = 0;
977  for (p = 0; p < m_np; p++) {
978  nsp = m_phase[p]->nSpecies();
979  const doublereal* x = DATA_PTR(m_moleFractions) + loc;
980  loc += nsp;
981  m_phase[p]->setState_TPX(m_temp, m_press, x);
982  m_temp_OK[p] = true;
983  if (m_temp < m_phase[p]->minTemp()
984  || m_temp > m_phase[p]->maxTemp()) {
985  m_temp_OK[p] = false;
986  }
987  }
988 }
989 }
std::map< std::string, doublereal > compositionMap
Map connecting a string name with a double.
Definition: ct_defs.h:149
XML_Node * get_XML_Node(const std::string &file_ID, XML_Node *root)
This routine will locate an XML node in either the input XML tree or in another input file specified ...
Definition: global.cpp:214
doublereal nAtoms(size_t k, size_t m) const
Number of atoms of element m in species k.
Definition: Phase.cpp:243
ThermoPhase * newPhase(XML_Node &xmlphase)
Create a new ThermoPhase object and initializes it according to the XML tree.
Array size error.
Definition: ctexceptions.h:154
std::string int2str(const int n, const std::string &fmt)
Convert an int to a string using a format converter.
Definition: stringUtils.cpp:39
std::vector< size_t > m_spphase
Mapping between the global species number and the phase ID.
Definition: MultiPhase.h:616
doublereal m_temp
Current value of the temperature (kelvin)
Definition: MultiPhase.h:655
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:105
size_t nElements() const
Number of elements.
Definition: Phase.cpp:167
bool tempOK(size_t p) const
Return true if the phase p has valid thermo data for the current temperature.
Definition: MultiPhase.cpp:958
MultiPhase()
Constructor.
Definition: MultiPhase.cpp:18
bool m_init
True if the init() routine has been called, and the MultiPhase frozen.
Definition: MultiPhase.h:667
virtual void setState_TPX(doublereal t, doublereal p, const doublereal *x)
Set the temperature (K), pressure (Pa), and mole fractions.
void setPhaseMoles(const size_t n, const doublereal moles)
Set the number of moles of phase with index n.
Definition: MultiPhase.cpp:943
doublereal speciesMoles(size_t kGlob) const
Returns the moles of global species k. units = kmol.
Definition: MultiPhase.cpp:247
void checkElementIndex(size_t m) const
Check that the specified element index is in range.
Definition: MultiPhase.cpp:861
std::map< std::string, size_t > m_enamemap
Returns the global element index, given the element string name.
Definition: MultiPhase.h:649
const size_t npos
index returned by functions to indicate "no position"
Definition: ct_defs.h:165
std::string speciesName(const size_t kGlob) const
Name of species with global index kGlob.
Definition: MultiPhase.cpp:904
void checkSpeciesArraySize(size_t kk) const
Check that an array size is at least nSpecies().
Definition: MultiPhase.cpp:897
vector_int m_atomicNumber
Atomic number of each element.
Definition: MultiPhase.h:636
doublereal phaseMoles(const size_t n) const
Return the number of moles in phase n.
Definition: MultiPhase.cpp:938
void addPhase(ThermoPhase *p, doublereal moles)
Add a phase to the mixture.
Definition: MultiPhase.cpp:91
Class XML_Node is a tree-based representation of the contents of an XML file.
Definition: xml.h:100
void warn_deprecated(const std::string &method, const std::string &extra)
Print a warning indicating that method is deprecated.
Definition: global.cpp:78
doublereal phaseCharge(size_t p) const
Charge (Coulombs) of phase with index p.
Definition: MultiPhase.cpp:295
doublereal equilibrate(int XY, doublereal err=1.0e-9, int maxsteps=1000, int maxiter=200, int loglevel=-99)
Set the mixture to a state of chemical equilibrium.
Definition: MultiPhase.cpp:561
int phaseIndex(const std::string &pName) const
Returns the index, given the phase name.
Definition: MultiPhase.cpp:925
void getMoleFractions(doublereal *const x) const
Get the species mole fraction vector.
Definition: Phase.cpp:556
Headers for the MultiPhase object that is used to set up multiphase equilibrium problems (see Equilib...
void getChemPotentials(doublereal *mu) const
Returns a vector of Chemical potentials.
Definition: MultiPhase.cpp:306
void checkPhaseArraySize(size_t mm) const
Check that an array size is at least nPhases() Throws an exception if mm is less than nPhases()...
Definition: MultiPhase.cpp:240
const doublereal Undef
Fairly random number to be used to initialize variables against to see if they are subsequently defin...
Definition: ct_defs.h:134
vector_fp m_moles
Vector of the number of moles in each phase.
Definition: MultiPhase.h:592
Base class for a phase with thermodynamic properties.
Definition: ThermoPhase.h:97
void getMoleFractions(doublereal *const x) const
Returns the global Species mole fractions.
Definition: MultiPhase.cpp:914
size_t speciesPhaseIndex(const size_t kGlob) const
Returns the phase index of the Kth "global" species.
Definition: MultiPhase.cpp:948
std::vector< std::string > m_enames
String names of the global elements.
Definition: MultiPhase.h:630
doublereal gibbs() const
The Gibbs function of the mixture [J].
Definition: MultiPhase.cpp:346
void addSpeciesMoles(const int indexS, const doublereal addedMoles)
Adds moles of a certain species to the mixture.
Definition: MultiPhase.cpp:490
vector_fp m_moleFractions
Locally stored vector of mole fractions of all species comprising the MultiPhase object.
Definition: MultiPhase.h:609
Cantera's Interface to the Multiphase chemical equilibrium solver.
void uploadMoleFractionsFromPhases()
Update the locally-stored composition within this object to match the current compositions of the pha...
Definition: MultiPhase.cpp:963
A class for multiphase mixtures.
Definition: MultiPhase.h:53
void resize(size_t n, size_t m, doublereal v=0.0)
Resize the matrix.
Definition: DenseMatrix.cpp:64
void checkPhaseIndex(size_t m) const
Check that the specified phase index is in range Throws an exception if m is greater than nPhases() ...
Definition: MultiPhase.cpp:233
doublereal charge() const
Total charge summed over all phases (Coulombs).
Definition: MultiPhase.cpp:269
std::vector< bool > m_temp_OK
Vector of bools indicating whether temperatures are ok for phases.
Definition: MultiPhase.h:680
void setState_TPMoles(const doublereal T, const doublereal Pres, const doublereal *Moles)
Set the state of the underlying ThermoPhase objects in one call.
Definition: MultiPhase.cpp:509
void checkSpeciesIndex(size_t k) const
Check that the specified species index is in range.
Definition: MultiPhase.cpp:890
std::string elementName(size_t m) const
Returns the name of the global element m.
Definition: MultiPhase.cpp:875
size_t m_eloc
Global ID of the element corresponding to the electronic charge.
Definition: MultiPhase.h:673
void getValidChemPotentials(doublereal not_mu, doublereal *mu, bool standard=false) const
Returns a vector of Valid chemical potentials.
Definition: MultiPhase.cpp:316
doublereal entropy() const
The entropy of the mixture [J/K].
Definition: MultiPhase.cpp:385
virtual doublereal maxTemp(size_t k=npos) const
Maximum temperature for which the thermodynamic data for the species are valid.
Definition: ThermoPhase.h:207
void addPhases(std::vector< ThermoPhase * > &phases, const vector_fp &phaseMoles)
Add a vector of phases to the mixture.
Definition: MultiPhase.cpp:80
DenseMatrix m_atoms
Global Stoichiometric Coefficient array.
Definition: MultiPhase.h:603
int atomicNumber(size_t m) const
Atomic number of element m.
Definition: Phase.cpp:226
std::vector< size_t > m_spstart
Vector of ints containing of first species index in the global list of species for each phase...
Definition: MultiPhase.h:624
void setPhaseMoleFractions(const size_t n, const doublereal *const x)
Set the Mole fractions of the nth phase.
Definition: MultiPhase.cpp:411
size_t m_nsp
Number of distinct species in all of the phases.
Definition: MultiPhase.h:664
void calcElemAbundances() const
Calculate the element abundance vector.
Definition: MultiPhase.cpp:526
std::string id() const
Return the string id for the phase.
Definition: Phase.cpp:147
size_t m_nel
Number of distinct elements in all of the phases.
Definition: MultiPhase.h:661
void setTemperature(const doublereal T)
Set the temperature [K].
Definition: MultiPhase.cpp:852
Base class for exceptions thrown by Cantera classes.
Definition: ctexceptions.h:99
void checkElementArraySize(size_t mm) const
Check that an array size is at least nElements().
Definition: MultiPhase.cpp:868
double equilibrate_MultiPhaseEquil(int XY, doublereal err, int maxsteps, int maxiter, int loglevel)
Set the mixture to a state of chemical equilibrium using the MultiPhaseEquil solver.
Definition: MultiPhase.cpp:570
int equilibrate(int XY, int estimateEquil=0, int printLvl=0, doublereal err=1.0e-6, int maxsteps=VCS_MAXSTEPS, int loglevel=-99)
Equilibrate the solution using the current element abundances stored in the MultiPhase object...
size_t elementIndex(const std::string &name) const
Returns the index of the element with name name.
Definition: MultiPhase.cpp:880
const U & getValue(const std::map< T, U > &m, const T &key)
Const accessor for a value in a std::map.
Definition: utilities.h:714
doublereal IntEnergy() const
The internal energy of the mixture [J].
Definition: MultiPhase.cpp:372
size_t m_np
Number of phases in the MultiPhase object.
Definition: MultiPhase.h:652
vector_fp m_elemAbundances
Vector of element abundances.
Definition: MultiPhase.h:700
std::vector< ThermoPhase * > m_phase
Vector of the ThermoPhase pointers.
Definition: MultiPhase.h:595
void getMoles(doublereal *molNum) const
Get the mole numbers of all species in the multiphase object.
Definition: MultiPhase.cpp:441
void setMolesByName(const compositionMap &xMap)
Set the number of moles of species in the mixture.
Definition: MultiPhase.cpp:424
doublereal nAtoms(const size_t kGlob, const size_t mGlob) const
Returns the Number of atoms of global element mGlob in global species kGlob.
Definition: MultiPhase.cpp:909
void setPressure(doublereal P)
Set the pressure [Pa].
Definition: MultiPhase.h:424
doublereal moleFraction(const size_t kGlob) const
Returns the mole fraction of global species k.
Definition: MultiPhase.cpp:953
size_t nSpecies() const
Returns the number of species in the phase.
Definition: Phase.h:265
Interface class for the vcsnonlinear solver.
void updatePhases() const
Set the states of the phase objects to the locally-stored state within this MultiPhase object...
Definition: MultiPhase.cpp:974
void setState_TP(const doublereal T, const doublereal Pres)
Set the state of the underlying ThermoPhase objects in one call.
Definition: MultiPhase.cpp:499
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.
virtual doublereal pressure() const
Return the thermodynamic pressure (Pa).
Definition: ThermoPhase.h:278
doublereal temperature() const
Temperature (K).
Definition: Phase.h:602
doublereal enthalpy() const
The enthalpy of the mixture [J].
Definition: MultiPhase.cpp:359
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:157
size_t elementIndex(const std::string &name) const
Return the index of element named 'name'.
Definition: Phase.cpp:192
doublereal maxTemp() const
Maximum temperature for which all solution phases have valid thermo data.
Definition: MultiPhase.h:257
doublereal cp() const
Heat capacity at constant pressure [J/K].
Definition: MultiPhase.cpp:398
std::string phaseName(const size_t iph) const
Returns the name of the n'th phase.
Definition: MultiPhase.cpp:919
doublereal elementMoles(size_t m) const
Total moles of global element m, summed over all phases.
Definition: MultiPhase.cpp:253
void init()
Process phases and build atomic composition array.
Definition: MultiPhase.cpp:160
Contains declarations for string manipulation functions within Cantera.
#define DATA_PTR(vec)
Creates a pointer to the start of the raw data for a vector.
Definition: ct_defs.h:36
std::vector< std::string > m_snames
Vector of species names in the problem.
Definition: MultiPhase.h:643
std::string elementName(size_t m) const
Name of the element with index m.
Definition: Phase.cpp:186
void writelog(const std::string &msg)
Write a message to the screen.
Definition: global.cpp:33
An array index is out of range.
Definition: ctexceptions.h:184
int _equilflag(const char *xy)
map property strings to integers
Definition: ChemEquil.cpp:24
bool solutionSpecies(size_t kGlob) const
Return true is species kGlob is a species in a multicomponent solution phase.
Definition: MultiPhase.cpp:337
thermo_t & phase(size_t n)
Return a reference to phase n.
Definition: MultiPhase.cpp:222
doublereal minTemp() const
Minimum temperature for which all solution phases have valid thermo data.
Definition: MultiPhase.h:250
doublereal m_press
Current value of the pressure (Pa)
Definition: MultiPhase.h:658
doublereal pressure() const
Pressure [Pa].
Definition: MultiPhase.h:409
void getElemAbundances(doublereal *elemAbundances) const
Retrieves a vector of element abundances.
Definition: MultiPhase.cpp:517
size_t nSpecies() const
Number of species, summed over all phases.
Definition: MultiPhase.h:124
size_t speciesIndex(size_t k, size_t p) const
Return the global index of the species belonging to phase number p with local index k within the phas...
Definition: MultiPhase.h:230
doublereal m_Tmax
Minimum temperature for which thermo parameterizations are valid.
Definition: MultiPhase.h:693
doublereal m_Tmin
Minimum temperature for which thermo parameterizations are valid.
Definition: MultiPhase.h:687
std::string speciesName(size_t k) const
Name of the species with index k.
Definition: Phase.cpp:272
Chemical equilibrium.
void setMoles(const doublereal *n)
Sets all of the global species mole numbers.
Definition: MultiPhase.cpp:459
doublereal volume() const
The total mixture volume [m^3].
Definition: MultiPhase.cpp:550
virtual doublereal minTemp(size_t k=npos) const
Minimum temperature for which the thermodynamic data for the species or phase are valid...
Definition: ThermoPhase.h:166
size_t nPhases() const
Number of phases.
Definition: MultiPhase.h:446
void save()
Function to put this error onto Cantera's error stack.