Cantera  2.0
IdealGasPhase.cpp
Go to the documentation of this file.
1 /**
2  * @file IdealGasPhase.cpp
3  * ThermoPhase object for the ideal gas equation of
4  * state - workhorse for %Cantera (see \ref thermoprops
5  * and class \link Cantera::IdealGasPhase IdealGasPhase\endlink).
6  */
7 
8 #include "cantera/base/ct_defs.h"
9 #include "cantera/thermo/mix_defs.h"
12 
13 using namespace std;
14 
15 namespace Cantera
16 {
17 // Default empty Constructor
18 IdealGasPhase::IdealGasPhase():
19  m_mm(0),
20  m_tmin(0.0),
21  m_tmax(0.0),
22  m_p0(-1.0),
23  m_tlast(0.0),
24  m_logc0(0.0)
25 {
26 }
27 
28 // Copy Constructor
30  m_mm(right.m_mm),
31  m_tmin(right.m_tmin),
32  m_tmax(right.m_tmax),
33  m_p0(right.m_p0),
34  m_tlast(right.m_tlast),
35  m_logc0(right.m_logc0)
36 {
37  /*
38  * Use the assignment operator to do the brunt
39  * of the work for the copy constructor.
40  */
41  *this = right;
42 }
43 
44 // Assignment operator
45 /*
46  * Assignment operator for the object. Constructed
47  * object will be a clone of this object, but will
48  * also own all of its data.
49  *
50  * @param right Object to be copied.
51  */
53 operator=(const IdealGasPhase& right)
54 {
55  if (&right != this) {
57  m_mm = right.m_mm;
58  m_tmin = right.m_tmin;
59  m_tmax = right.m_tmax;
60  m_p0 = right.m_p0;
61  m_tlast = right.m_tlast;
62  m_logc0 = right.m_logc0;
63  m_h0_RT = right.m_h0_RT;
64  m_cp0_R = right.m_cp0_R;
65  m_g0_RT = right.m_g0_RT;
66  m_s0_R = right.m_s0_R;
67  m_expg0_RT= right.m_expg0_RT;
68  m_pe = right.m_pe;
69  m_pp = right.m_pp;
70  }
71  return *this;
72 }
73 
74 // Duplicator from the %ThermoPhase parent class
75 /*
76  * Given a pointer to a %ThermoPhase object, this function will
77  * duplicate the %ThermoPhase object and all underlying structures.
78  * This is basically a wrapper around the copy constructor.
79  *
80  * @return returns a pointer to a %ThermoPhase
81  */
83 {
84  ThermoPhase* igp = new IdealGasPhase(*this);
85  return (ThermoPhase*) igp;
86 }
87 
88 // Molar Thermodynamic Properties of the Solution ------------------
89 
90 /*
91  * Molar internal energy. J/kmol. For an ideal gas mixture,
92  * \f[
93  * \hat u(T) = \sum_k X_k \hat h^0_k(T) - \hat R T,
94  * \f]
95  * and is a function only of temperature.
96  * The reference-state pure-species enthalpies
97  * \f$ \hat h^0_k(T) \f$ are computed by the species thermodynamic
98  * property manager.
99  * @see SpeciesThermo
100  */
102 {
103  return GasConstant * temperature()
104  * (mean_X(&enthalpy_RT_ref()[0]) - 1.0);
105 }
106 
107 /*
108  * Molar entropy. Units: J/kmol/K.
109  * For an ideal gas mixture,
110  * \f[
111  * \hat s(T, P) = \sum_k X_k \hat s^0_k(T) - \hat R \log (P/P^0).
112  * \f]
113  * The reference-state pure-species entropies
114  * \f$ \hat s^0_k(T) \f$ are computed by the species thermodynamic
115  * property manager.
116  * @see SpeciesThermo
117  */
118 doublereal IdealGasPhase::entropy_mole() const
119 {
120  return GasConstant * (mean_X(&entropy_R_ref()[0]) -
121  sum_xlogx() - std::log(pressure()/m_spthermo->refPressure()));
122 }
123 
124 /*
125  * Molar Gibbs free Energy for an ideal gas.
126  * Units = J/kmol.
127  */
128 doublereal IdealGasPhase::gibbs_mole() const
129 {
130  return enthalpy_mole() - temperature() * entropy_mole();
131 }
132 
133 /*
134  * Molar heat capacity at constant pressure. Units: J/kmol/K.
135  * For an ideal gas mixture,
136  * \f[
137  * \hat c_p(t) = \sum_k \hat c^0_{p,k}(T).
138  * \f]
139  * The reference-state pure-species heat capacities
140  * \f$ \hat c^0_{p,k}(T) \f$ are computed by the species thermodynamic
141  * property manager.
142  * @see SpeciesThermo
143  */
144 doublereal IdealGasPhase::cp_mole() const
145 {
146  return GasConstant * mean_X(&cp_R_ref()[0]);
147 }
148 
149 /*
150  * Molar heat capacity at constant volume. Units: J/kmol/K.
151  * For an ideal gas mixture,
152  * \f[ \hat c_v = \hat c_p - \hat R. \f]
153  */
154 doublereal IdealGasPhase::cv_mole() const
155 {
156  return cp_mole() - GasConstant;
157 }
158 
159 // Mechanical Equation of State ----------------------------
160 // Chemical Potentials and Activities ----------------------
161 
162 /*
163  * Returns the standard concentration \f$ C^0_k \f$, which is used to normalize
164  * the generalized concentration.
165  */
166 doublereal IdealGasPhase::standardConcentration(size_t k) const
167 {
168  double p = pressure();
169  return p/(GasConstant * temperature());
170 }
171 
172 /*
173  * Returns the natural logarithm of the standard
174  * concentration of the kth species
175  */
176 doublereal IdealGasPhase::logStandardConc(size_t k) const
177 {
178  _updateThermo();
179  double p = pressure();
180  double lc = std::log(p / (GasConstant * temperature()));
181  return lc;
182 }
183 
184 /*
185  * Get the array of non-dimensional activity coefficients
186  */
187 void IdealGasPhase::getActivityCoefficients(doublereal* ac) const
188 {
189  for (size_t k = 0; k < m_kk; k++) {
190  ac[k] = 1.0;
191  }
192 }
193 
194 /*
195  * Get the array of chemical potentials at unit activity \f$
196  * \mu^0_k(T,P) \f$.
197  */
198 void IdealGasPhase::getStandardChemPotentials(doublereal* muStar) const
199 {
200  const vector_fp& gibbsrt = gibbs_RT_ref();
201  scale(gibbsrt.begin(), gibbsrt.end(), muStar, _RT());
202  double tmp = log(pressure() /m_spthermo->refPressure());
203  tmp *= GasConstant * temperature();
204  for (size_t k = 0; k < m_kk; k++) {
205  muStar[k] += tmp; // add RT*ln(P/P_0)
206  }
207 }
208 
209 // Partial Molar Properties of the Solution --------------
210 
211 void IdealGasPhase::getChemPotentials(doublereal* mu) const
212 {
214  //doublereal logp = log(pressure()/m_spthermo->refPressure());
215  doublereal xx;
216  doublereal rt = temperature() * GasConstant;
217  //const vector_fp& g_RT = gibbs_RT_ref();
218  for (size_t k = 0; k < m_kk; k++) {
220  mu[k] += rt*(log(xx));
221  }
222 }
223 
224 /*
225  * Get the array of partial molar enthalpies of the species
226  * units = J / kmol
227  */
228 void IdealGasPhase::getPartialMolarEnthalpies(doublereal* hbar) const
229 {
230  const vector_fp& _h = enthalpy_RT_ref();
231  doublereal rt = GasConstant * temperature();
232  scale(_h.begin(), _h.end(), hbar, rt);
233 }
234 
235 /*
236  * Get the array of partial molar entropies of the species
237  * units = J / kmol / K
238  */
239 void IdealGasPhase::getPartialMolarEntropies(doublereal* sbar) const
240 {
241  const vector_fp& _s = entropy_R_ref();
242  doublereal r = GasConstant;
243  scale(_s.begin(), _s.end(), sbar, r);
244  doublereal logp = log(pressure()/m_spthermo->refPressure());
245  for (size_t k = 0; k < m_kk; k++) {
246  doublereal xx = std::max(SmallNumber, moleFraction(k));
247  sbar[k] += r * (- logp - log(xx));
248  }
249 }
250 
251 /*
252  * Get the array of partial molar internal energies of the species
253  * units = J / kmol
254  */
255 void IdealGasPhase::getPartialMolarIntEnergies(doublereal* ubar) const
256 {
257  const vector_fp& _h = enthalpy_RT_ref();
258  doublereal rt = GasConstant * temperature();
259  for (size_t k = 0; k < m_kk; k++) {
260  ubar[k] = rt * (_h[k] - 1.0);
261  }
262 }
263 
264 /*
265  * Get the array of partial molar heat capacities
266  */
267 void IdealGasPhase::getPartialMolarCp(doublereal* cpbar) const
268 {
269  const vector_fp& _cp = cp_R_ref();
270  scale(_cp.begin(), _cp.end(), cpbar, GasConstant);
271 }
272 
273 /*
274  * Get the array of partial molar volumes
275  * units = m^3 / kmol
276  */
277 void IdealGasPhase::getPartialMolarVolumes(doublereal* vbar) const
278 {
279  double vol = 1.0 / molarDensity();
280  for (size_t k = 0; k < m_kk; k++) {
281  vbar[k] = vol;
282  }
283 }
284 
285 // Properties of the Standard State of the Species in the Solution --
286 
287 /*
288  * Get the nondimensional Enthalpy functions for the species
289  * at their standard states at the current T and P of the
290  * solution
291  */
292 void IdealGasPhase::getEnthalpy_RT(doublereal* hrt) const
293 {
294  const vector_fp& _h = enthalpy_RT_ref();
295  copy(_h.begin(), _h.end(), hrt);
296 }
297 
298 /*
299  * Get the array of nondimensional entropy functions for the
300  * standard state species
301  * at the current <I>T</I> and <I>P</I> of the solution.
302  */
303 void IdealGasPhase::getEntropy_R(doublereal* sr) const
304 {
305  const vector_fp& _s = entropy_R_ref();
306  copy(_s.begin(), _s.end(), sr);
307  double tmp = log(pressure() /m_spthermo->refPressure());
308  for (size_t k = 0; k < m_kk; k++) {
309  sr[k] -= tmp;
310  }
311 }
312 
313 /*
314  * Get the nondimensional gibbs function for the species
315  * standard states at the current T and P of the solution.
316  */
317 void IdealGasPhase::getGibbs_RT(doublereal* grt) const
318 {
319  const vector_fp& gibbsrt = gibbs_RT_ref();
320  copy(gibbsrt.begin(), gibbsrt.end(), grt);
321  double tmp = log(pressure() /m_spthermo->refPressure());
322  for (size_t k = 0; k < m_kk; k++) {
323  grt[k] += tmp;
324  }
325 }
326 
327 /*
328  * get the pure Gibbs free energies of each species assuming
329  * it is in its standard state. This is the same as
330  * getStandardChemPotentials().
331  */
332 void IdealGasPhase::getPureGibbs(doublereal* gpure) const
333 {
334  const vector_fp& gibbsrt = gibbs_RT_ref();
335  scale(gibbsrt.begin(), gibbsrt.end(), gpure, _RT());
336  double tmp = log(pressure() /m_spthermo->refPressure());
337  tmp *= _RT();
338  for (size_t k = 0; k < m_kk; k++) {
339  gpure[k] += tmp;
340  }
341 }
342 
343 /*
344  * Returns the vector of nondimensional
345  * internal Energies of the standard state at the current temperature
346  * and pressure of the solution for each species.
347  */
348 void IdealGasPhase::getIntEnergy_RT(doublereal* urt) const
349 {
350  const vector_fp& _h = enthalpy_RT_ref();
351  for (size_t k = 0; k < m_kk; k++) {
352  urt[k] = _h[k] - 1.0;
353  }
354 }
355 
356 /*
357  * Get the nondimensional heat capacity at constant pressure
358  * function for the species
359  * standard states at the current T and P of the solution.
360  */
361 void IdealGasPhase::getCp_R(doublereal* cpr) const
362 {
363  const vector_fp& _cpr = cp_R_ref();
364  copy(_cpr.begin(), _cpr.end(), cpr);
365 }
366 
367 /*
368  * Get the molar volumes of the species standard states at the current
369  * <I>T</I> and <I>P</I> of the solution.
370  * units = m^3 / kmol
371  *
372  * @param vol Output vector containing the standard state volumes.
373  * Length: m_kk.
374  */
375 void IdealGasPhase::getStandardVolumes(doublereal* vol) const
376 {
377  double tmp = 1.0 / molarDensity();
378  for (size_t k = 0; k < m_kk; k++) {
379  vol[k] = tmp;
380  }
381 }
382 
383 // Thermodynamic Values for the Species Reference States ---------
384 
385 /*
386  * Returns the vector of nondimensional
387  * enthalpies of the reference state at the current temperature
388  * and reference pressure.
389  */
390 void IdealGasPhase::getEnthalpy_RT_ref(doublereal* hrt) const
391 {
392  const vector_fp& _h = enthalpy_RT_ref();
393  copy(_h.begin(), _h.end(), hrt);
394 }
395 
396 /*
397  * Returns the vector of nondimensional
398  * enthalpies of the reference state at the current temperature
399  * and reference pressure.
400  */
401 void IdealGasPhase::getGibbs_RT_ref(doublereal* grt) const
402 {
403  const vector_fp& gibbsrt = gibbs_RT_ref();
404  copy(gibbsrt.begin(), gibbsrt.end(), grt);
405 }
406 
407 /*
408  * Returns the vector of the
409  * gibbs function of the reference state at the current temperature
410  * and reference pressure.
411  * units = J/kmol
412  */
413 void IdealGasPhase::getGibbs_ref(doublereal* g) const
414 {
415  const vector_fp& gibbsrt = gibbs_RT_ref();
416  scale(gibbsrt.begin(), gibbsrt.end(), g, _RT());
417 }
418 
419 /*
420  * Returns the vector of nondimensional
421  * entropies of the reference state at the current temperature
422  * and reference pressure.
423  */
424 void IdealGasPhase::getEntropy_R_ref(doublereal* er) const
425 {
426  const vector_fp& _s = entropy_R_ref();
427  copy(_s.begin(), _s.end(), er);
428 }
429 
430 /*
431  * Returns the vector of nondimensional
432  * internal Energies of the reference state at the current temperature
433  * of the solution and the reference pressure for each species.
434  */
435 void IdealGasPhase::getIntEnergy_RT_ref(doublereal* urt) const
436 {
437  const vector_fp& _h = enthalpy_RT_ref();
438  for (size_t k = 0; k < m_kk; k++) {
439  urt[k] = _h[k] - 1.0;
440  }
441 }
442 
443 /*
444  * Returns the vector of nondimensional
445  * constant pressure heat capacities of the reference state
446  * at the current temperature and reference pressure.
447  */
448 void IdealGasPhase::getCp_R_ref(doublereal* cprt) const
449 {
450  const vector_fp& _cpr = cp_R_ref();
451  copy(_cpr.begin(), _cpr.end(), cprt);
452 }
453 
454 void IdealGasPhase::getStandardVolumes_ref(doublereal* vol) const
455 {
456  doublereal tmp = _RT() / m_p0;
457  for (size_t k = 0; k < m_kk; k++) {
458  vol[k] = tmp;
459  }
460 }
461 
462 
463 // new methods defined here -------------------------------
464 
465 
467 {
468 
469  m_mm = nElements();
470  doublereal tmin = m_spthermo->minTemp();
471  doublereal tmax = m_spthermo->maxTemp();
472  if (tmin > 0.0) {
473  m_tmin = tmin;
474  }
475  if (tmax > 0.0) {
476  m_tmax = tmax;
477  }
478  m_p0 = refPressure();
479 
480  m_h0_RT.resize(m_kk);
481  m_g0_RT.resize(m_kk);
482  m_expg0_RT.resize(m_kk);
483  m_cp0_R.resize(m_kk);
484  m_s0_R.resize(m_kk);
485  m_pe.resize(m_kk, 0.0);
486  m_pp.resize(m_kk);
487 }
488 
489 /*
490  * Set mixture to an equilibrium state consistent with specified
491  * chemical potentials and temperature. This method is needed by
492  * the ChemEquil equilibrium solver.
493  */
494 void IdealGasPhase::setToEquilState(const doublereal* mu_RT)
495 {
496  double tmp, tmp2;
497  const vector_fp& grt = gibbs_RT_ref();
498 
499  /*
500  * Within the method, we protect against inf results if the
501  * exponent is too high.
502  *
503  * If it is too low, we set
504  * the partial pressure to zero. This capability is needed
505  * by the elemental potential method.
506  */
507  doublereal pres = 0.0;
508  for (size_t k = 0; k < m_kk; k++) {
509  tmp = -grt[k] + mu_RT[k];
510  if (tmp < -600.) {
511  m_pp[k] = 0.0;
512  } else if (tmp > 500.0) {
513  tmp2 = tmp / 500.;
514  tmp2 *= tmp2;
515  m_pp[k] = m_p0 * exp(500.) * tmp2;
516  } else {
517  m_pp[k] = m_p0 * exp(tmp);
518  }
519  pres += m_pp[k];
520  }
521  // set state
522  setState_PX(pres, &m_pp[0]);
523 }
524 
525 
526 /// This method is called each time a thermodynamic property is
527 /// requested, to check whether the internal species properties
528 /// within the object need to be updated.
529 /// Currently, this updates the species thermo polynomial values
530 /// for the current value of the temperature. A check is made
531 /// to see if the temperature has changed since the last
532 /// evaluation. This object does not contain any persistent
533 /// data that depends on the concentration, that needs to be
534 /// updated. The state object modifies its concentration
535 /// dependent information at the time the setMoleFractions()
536 /// (or equivalent) call is made.
538 {
539  doublereal tnow = temperature();
540 
541  // If the temperature has changed since the last time these
542  // properties were computed, recompute them.
543  if (m_tlast != tnow) {
544  m_spthermo->update(tnow, &m_cp0_R[0], &m_h0_RT[0],
545  &m_s0_R[0]);
546  m_tlast = tnow;
547 
548  // update the species Gibbs functions
549  for (size_t k = 0; k < m_kk; k++) {
550  m_g0_RT[k] = m_h0_RT[k] - m_s0_R[k];
551  }
552  m_logc0 = log(m_p0/(GasConstant * tnow));
553  m_tlast = tnow;
554  }
555 }
556 }
557