Cantera  2.2.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
MixtureFugacityTP.cpp
Go to the documentation of this file.
1 /**
2  * @file MixtureFugacityTP.cpp
3  * Methods file for a derived class of ThermoPhase that handles
4  * non-ideal mixtures based on the fugacity models (see \ref thermoprops and
5  * class \link Cantera::MixtureFugacityTP MixtureFugacityTP\endlink).
6  */
7 /*
8  * Copyright (2005) Sandia Corporation. Under the terms of
9  * Contract DE-AC04-94AL85000 with Sandia Corporation, the
10  * U.S. Government retains certain rights in this software.
11  */
12 
15 #include "cantera/base/ctml.h"
17 
18 using namespace std;
19 
20 namespace Cantera
21 {
22 
23 MixtureFugacityTP::MixtureFugacityTP() :
24  m_Pcurrent(-1.0),
25  iState_(FLUID_GAS),
26  forcedState_(FLUID_UNDEFINED),
27  m_Tlast_ref(-1.0),
28  m_logc0(0.0)
29 {
30 }
31 
33  m_Pcurrent(-1.0),
34  iState_(FLUID_GAS),
35  forcedState_(FLUID_UNDEFINED),
36  m_Tlast_ref(-1.0),
37  m_logc0(0.0)
38 {
40 }
41 
44 {
45  if (&b != this) {
46  /*
47  * Mostly, this is a passthrough to the underlying
48  * assignment operator for the ThermoPhase parent object.
49  */
51  /*
52  * However, we have to handle data that we own.
53  */
56  iState_ = b.iState_;
59  m_logc0 = b.m_logc0;
60  m_h0_RT = b.m_h0_RT;
61  m_cp0_R = b.m_cp0_R;
62  m_g0_RT = b.m_g0_RT;
63  m_s0_R = b.m_s0_R;
64  }
65  return *this;
66 }
67 
69 {
70  return new MixtureFugacityTP(*this);
71 }
72 
74 {
76 }
77 
79 {
80  forcedState_ = solnBranch;
81 }
82 
84 {
85  return forcedState_;
86 }
87 
89 {
90  return iState_;
91 }
92 
93 /*
94  * ---- Partial Molar Properties of the Solution -----------------
95  */
96 
97 void MixtureFugacityTP::getChemPotentials_RT(doublereal* muRT) const
98 {
99  getChemPotentials(muRT);
100  doublereal invRT = 1.0 / _RT();
101  for (size_t k = 0; k < m_kk; k++) {
102  muRT[k] *= invRT;
103  }
104 }
105 
106 /*
107  * ----- Thermodynamic Values for the Species Standard States States ----
108  */
109 
111 {
113  copy(m_g0_RT.begin(), m_g0_RT.end(), g);
114  doublereal RT = _RT();
115  double tmp = log(pressure() /m_spthermo->refPressure());
116  for (size_t k = 0; k < m_kk; k++) {
117  g[k] = RT * (g[k] + tmp);
118  }
119 }
120 
121 void MixtureFugacityTP::getEnthalpy_RT(doublereal* hrt) const
122 {
123  getEnthalpy_RT_ref(hrt);
124 }
125 
126 void MixtureFugacityTP::modifyOneHf298SS(const size_t k, const doublereal Hf298New)
127 {
128  m_spthermo->modifyOneHf298(k, Hf298New);
129  m_Tlast_ref += 0.0001234;
130 }
131 
132 void MixtureFugacityTP::getEntropy_R(doublereal* sr) const
133 {
135  copy(m_s0_R.begin(), m_s0_R.end(), sr);
136  double tmp = log(pressure() /m_spthermo->refPressure());
137  for (size_t k = 0; k < m_kk; k++) {
138  sr[k] -= tmp;
139  }
140 }
141 
142 void MixtureFugacityTP::getGibbs_RT(doublereal* grt) const
143 {
145  copy(m_g0_RT.begin(), m_g0_RT.end(), grt);
146  double tmp = log(pressure() /m_spthermo->refPressure());
147  for (size_t k = 0; k < m_kk; k++) {
148  grt[k] += tmp;
149  }
150 }
151 
152 void MixtureFugacityTP::getPureGibbs(doublereal* g) const
153 {
155  scale(m_g0_RT.begin(), m_g0_RT.end(), g, _RT());
156  double tmp = log(pressure() /m_spthermo->refPressure()) * _RT();
157  for (size_t k = 0; k < m_kk; k++) {
158  g[k] += tmp;
159  }
160 }
161 
162 void MixtureFugacityTP::getIntEnergy_RT(doublereal* urt) const
163 {
165  copy(m_h0_RT.begin(), m_h0_RT.end(), urt);
166  for (size_t i = 0; i < m_kk; i++) {
167  urt[i] -= 1.0;
168  }
169 }
170 
171 void MixtureFugacityTP::getCp_R(doublereal* cpr) const
172 {
174  copy(m_cp0_R.begin(), m_cp0_R.end(), cpr);
175 }
176 
177 void MixtureFugacityTP::getStandardVolumes(doublereal* vol) const
178 {
180  doublereal v0 = _RT() / pressure();
181  for (size_t i = 0; i < m_kk; i++) {
182  vol[i]= v0;
183  }
184 }
185 
186 /*
187  * ----- Thermodynamic Values for the Species Reference States ----
188  */
189 
190 
191 void MixtureFugacityTP::getEnthalpy_RT_ref(doublereal* hrt) const
192 {
194  copy(m_h0_RT.begin(), m_h0_RT.end(), hrt);
195 }
196 
197 void MixtureFugacityTP::getGibbs_RT_ref(doublereal* grt) const
198 {
200  copy(m_g0_RT.begin(), m_g0_RT.end(), grt);
201 }
202 
203 void MixtureFugacityTP::getGibbs_ref(doublereal* g) const
204 {
205  const vector_fp& gibbsrt = gibbs_RT_ref();
206  scale(gibbsrt.begin(), gibbsrt.end(), g, _RT());
207 }
208 
210 {
212  return m_g0_RT;
213 }
214 
215 void MixtureFugacityTP::getEntropy_R_ref(doublereal* er) const
216 {
218  copy(m_s0_R.begin(), m_s0_R.end(), er);
219 }
220 
221 void MixtureFugacityTP::getCp_R_ref(doublereal* cpr) const
222 {
224  copy(m_cp0_R.begin(), m_cp0_R.end(), cpr);
225 }
226 
227 void MixtureFugacityTP::getStandardVolumes_ref(doublereal* vol) const
228 {
230  doublereal v0 = _RT() / refPressure();
231  for (size_t i = 0; i < m_kk; i++) {
232  vol[i]= v0;
233  }
234 }
235 
237 {
238  int doTP = 0;
239  string comp = getChildValue(state,"moleFractions");
240  if (comp != "") {
241  // not overloaded in current object -> phase state is not calculated.
243  doTP = 1;
244  } else {
245  comp = getChildValue(state,"massFractions");
246  if (comp != "") {
247  // not overloaded in current object -> phase state is not calculated.
249  doTP = 1;
250  }
251  }
252  double t = temperature();
253  if (state.hasChild("temperature")) {
254  t = getFloat(state, "temperature", "temperature");
255  doTP = 1;
256  }
257  if (state.hasChild("pressure")) {
258  double p = getFloat(state, "pressure", "pressure");
259  setState_TP(t, p);
260  } else if (state.hasChild("density")) {
261  double rho = getFloat(state, "density", "density");
262  setState_TR(t, rho);
263  } else if (doTP) {
264  double rho = Phase::density();
265  setState_TR(t, rho);
266  }
267 }
268 
270 {
271  initLengths();
273 }
274 
276 {
277  moleFractions_.resize(m_kk, 0.0);
278  moleFractions_[0] = 1.0;
279  m_h0_RT.resize(m_kk, 0.0);
280  m_cp0_R.resize(m_kk, 0.0);
281  m_g0_RT.resize(m_kk, 0.0);
282  m_s0_R.resize(m_kk, 0.0);
283 }
284 
285 void MixtureFugacityTP::setTemperature(const doublereal temp)
286 {
289 }
290 
292 {
293  setState_TP(temperature(), p);
294  }
295 
296 void MixtureFugacityTP::setMassFractions(const doublereal* const y)
297 {
300 }
301 
302 void MixtureFugacityTP::setMassFractions_NoNorm(const doublereal* const y)
303 {
306 }
307 
308 void MixtureFugacityTP::setMoleFractions(const doublereal* const x)
309 {
312 }
313 
314 void MixtureFugacityTP::setMoleFractions_NoNorm(const doublereal* const x)
315 {
318 }
319 
320 void MixtureFugacityTP::setConcentrations(const doublereal* const c)
321 {
324 }
325 
326 void MixtureFugacityTP::setMoleFractions_NoState(const doublereal* const x)
327 {
330  updateMixingExpressions();
331 }
332 
334 {
335  throw NotImplementedError("MixtureFugacityTP::calcDensity() "
336  "called, but EOS for phase is not known");
337 }
338 
339 void MixtureFugacityTP::setState_TP(doublereal t, doublereal pres)
340 {
341  /*
342  * A pretty tricky algorithm is needed here, due to problems involving
343  * standard states of real fluids. For those cases you need
344  * to combine the T and P specification for the standard state, or else
345  * you may venture into the forbidden zone, especially when nearing the
346  * triple point.
347  * Therefore, we need to do the standard state thermo calc with the
348  * (t, pres) combo.
349  */
351 
352 
355  // Depends on the mole fractions and the temperature
356  updateMixingExpressions();
357  m_Pcurrent = pres;
358 
359  if (forcedState_ == FLUID_UNDEFINED) {
360  double rhoNow = Phase::density();
361  double rho = densityCalc(t, pres, iState_, rhoNow);
362  if (rho > 0.0) {
363  Phase::setDensity(rho);
364  m_Pcurrent = pres;
365  iState_ = phaseState(true);
366  } else {
367  if (rho < -1.5) {
368  rho = densityCalc(t, pres, FLUID_UNDEFINED , rhoNow);
369  if (rho > 0.0) {
370  Phase::setDensity(rho);
371  m_Pcurrent = pres;
372  iState_ = phaseState(true);
373  } else {
374  throw CanteraError("MixtureFugacityTP::setState_TP()", "neg rho");
375  }
376  } else {
377  throw CanteraError("MixtureFugacityTP::setState_TP()", "neg rho");
378  }
379  }
380 
381 
382 
383  } else if (forcedState_ == FLUID_GAS) {
384  // Normal density calculation
385  if (iState_ < FLUID_LIQUID_0) {
386  double rhoNow = Phase::density();
387  double rho = densityCalc(t, pres, iState_, rhoNow);
388  if (rho > 0.0) {
389  Phase::setDensity(rho);
390  m_Pcurrent = pres;
391  iState_ = phaseState(true);
392  if (iState_ >= FLUID_LIQUID_0) {
393  throw CanteraError("MixtureFugacityTP::setState_TP()", "wrong state");
394  }
395  } else {
396  throw CanteraError("MixtureFugacityTP::setState_TP()", "neg rho");
397  }
398 
399  }
400 
401 
402  } else if (forcedState_ > FLUID_LIQUID_0) {
403  if (iState_ >= FLUID_LIQUID_0) {
404  double rhoNow = Phase::density();
405  double rho = densityCalc(t, pres, iState_, rhoNow);
406  if (rho > 0.0) {
407  Phase::setDensity(rho);
408  m_Pcurrent = pres;
409  iState_ = phaseState(true);
410  if (iState_ == FLUID_GAS) {
411  throw CanteraError("MixtureFugacityTP::setState_TP()", "wrong state");
412  }
413  } else {
414  throw CanteraError("MixtureFugacityTP::setState_TP()", "neg rho");
415  }
416 
417  }
418  }
419 }
420 
421 void MixtureFugacityTP::setState_TR(doublereal T, doublereal rho)
422 {
426  Phase::setDensity(rho);
427  doublereal mv = molarVolume();
428  // depends on mole fraction and temperature
429  updateMixingExpressions();
430 
431  m_Pcurrent = pressureCalc(T, mv);
432  iState_ = phaseState(true);
433 }
434 
435 void MixtureFugacityTP::setState_TPX(doublereal t, doublereal p, const doublereal* x)
436 {
437  setMoleFractions_NoState(x);
438  setState_TP(t,p);
439 }
440 
441 void MixtureFugacityTP::initThermoXML(XML_Node& phaseNode, const std::string& id_)
442 {
444  ThermoPhase::initThermoXML(phaseNode, id_);
445 }
446 
447 doublereal MixtureFugacityTP::z() const
448 {
449  return pressure() * meanMolecularWeight() / (density() * _RT());
450 }
451 
452 doublereal MixtureFugacityTP::sresid() const
453 {
454  throw CanteraError("MixtureFugacityTP::sresid()", "Base Class: not implemented");
455 }
456 
457 doublereal MixtureFugacityTP::hresid() const
458 {
459  throw CanteraError("MixtureFugacityTP::hresid()", "Base Class: not implemented");
460 }
461 
462 doublereal MixtureFugacityTP::psatEst(doublereal TKelvin) const
463 {
464  doublereal pcrit = critPressure();
465  doublereal tt = critTemperature() / TKelvin;
466  if (tt < 1.0) {
467  return pcrit;
468  }
469  doublereal lpr = -0.8734*tt*tt - 3.4522*tt + 4.2918;
470  return pcrit*exp(lpr);
471 }
472 
473 doublereal MixtureFugacityTP::liquidVolEst(doublereal TKelvin, doublereal& pres) const
474 {
475  throw CanteraError("MixtureFugacityTP::liquidVolEst()", "unimplemented");
476 }
477 
478 doublereal MixtureFugacityTP::densityCalc(doublereal TKelvin, doublereal presPa,
479  int phase, doublereal rhoguess)
480 {
481  doublereal tcrit = critTemperature();
482  doublereal mmw = meanMolecularWeight();
483  if (rhoguess == -1.0) {
484  if (phase != -1) {
485  if (TKelvin > tcrit) {
486  rhoguess = presPa * mmw / (GasConstant * TKelvin);
487  } else {
488  if (phase == FLUID_GAS || phase == FLUID_SUPERCRIT) {
489  rhoguess = presPa * mmw / (GasConstant * TKelvin);
490  } else if (phase >= FLUID_LIQUID_0) {
491  double lqvol = liquidVolEst(TKelvin, presPa);
492  rhoguess = mmw / lqvol;
493  }
494  }
495  } else {
496  /*
497  * Assume the Gas phase initial guess, if nothing is
498  * specified to the routine
499  */
500  rhoguess = presPa * mmw / (GasConstant * TKelvin);
501  }
502 
503  }
504 
505  double molarVolBase = mmw / rhoguess;
506  double molarVolLast = molarVolBase;
507  double vc = mmw / critDensity();
508  /*
509  * molar volume of the spinodal at the current temperature and mole fractions. this will
510  * be updated as we go.
511  */
512  double molarVolSpinodal = vc;
513  bool conv = false;
514  /*
515  * We start on one side of the vc and stick with that side
516  */
517  bool gasSide = molarVolBase > vc;
518  if (gasSide) {
519  molarVolLast = (GasConstant * TKelvin)/presPa;
520  } else {
521  molarVolLast = liquidVolEst(TKelvin, presPa);
522  }
523 
524  /*
525  * OK, now we do a small solve to calculate the molar volume given the T,P value.
526  * The algorithm is taken from dfind()
527  */
528  for (int n = 0; n < 200; n++) {
529 
530  /*
531  * Calculate the predicted reduced pressure, pred0, based on the
532  * current tau and dd.
533  */
534 
535  /*
536  * Calculate the derivative of the predicted pressure
537  * wrt the molar volume.
538  * This routine also returns the pressure, presBase
539  */
540  double presBase;
541  double dpdVBase = dpdVCalc(TKelvin, molarVolBase, presBase);
542 
543  /*
544  * If dpdV is positive, then we are in the middle of the
545  * 2 phase region and beyond the spinodal stability curve. We need to adjust
546  * the initial guess outwards and start a new iteration.
547  */
548  if (dpdVBase >= 0.0) {
549  if (TKelvin > tcrit) {
550  throw CanteraError("MixtureFugacityTP::densityCalc",
551  "T > tcrit unexpectedly");
552  }
553  /*
554  * TODO Spawn a calculation for the value of the spinodal point that is
555  * very accurate. Answer the question as to whether a solution is
556  * possible on the current side of the vapor dome.
557  */
558  if (gasSide) {
559  if (molarVolBase >= vc) {
560  molarVolSpinodal = molarVolBase;
561  molarVolBase = 0.5 * (molarVolLast + molarVolSpinodal);
562  } else {
563  molarVolBase = 0.5 * (molarVolLast + molarVolSpinodal);
564  }
565  } else {
566  if (molarVolBase <= vc) {
567  molarVolSpinodal = molarVolBase;
568  molarVolBase = 0.5 * (molarVolLast + molarVolSpinodal);
569  } else {
570  molarVolBase = 0.5 * (molarVolLast + molarVolSpinodal);
571  }
572  }
573  continue;
574  }
575 
576  /*
577  * Check for convergence
578  */
579  if (fabs(presBase-presPa) < 1.0E-30 + 1.0E-8 * presPa) {
580  conv = true;
581  break;
582  }
583 
584  /*
585  * Dampen and crop the update
586  */
587  doublereal dpdV = dpdVBase;
588  if (n < 10) {
589  dpdV = dpdVBase * 1.5;
590  }
591 
592  /*
593  * Formulate the update to the molar volume by
594  * Newton's method. Then, crop it to a max value
595  * of 0.1 times the current volume
596  */
597  double delMV = - (presBase - presPa) / dpdV;
598  if (!gasSide || delMV < 0.0) {
599  if (fabs(delMV) > 0.2 * molarVolBase) {
600  delMV = delMV / fabs(delMV) * 0.2 * molarVolBase;
601  }
602  }
603  /*
604  * Only go 1/10 the way towards the spinodal at any one time.
605  */
606  if (TKelvin < tcrit) {
607  if (gasSide) {
608  if (delMV < 0.0) {
609  if (-delMV > 0.5 * (molarVolBase - molarVolSpinodal)) {
610  delMV = - 0.5 * (molarVolBase - molarVolSpinodal);
611  }
612  }
613  } else {
614  if (delMV > 0.0) {
615  if (delMV > 0.5 * (molarVolSpinodal - molarVolBase)) {
616  delMV = 0.5 * (molarVolSpinodal - molarVolBase);
617  }
618  }
619  }
620  }
621  /*
622  * updated the molar volume value
623  */
624  molarVolLast = molarVolBase;
625  molarVolBase += delMV;
626 
627 
628  if (fabs(delMV/molarVolBase) < 1.0E-14) {
629  conv = true;
630  break;
631  }
632 
633  /*
634  * Check for negative molar volumes
635  */
636  if (molarVolBase <= 0.0) {
637  molarVolBase = std::min(1.0E-30, fabs(delMV*1.0E-4));
638  }
639 
640  }
641 
642 
643  /*
644  * Check for convergence, and return 0.0 if it wasn't achieved.
645  */
646  double densBase = 0.0;
647  if (! conv) {
648  molarVolBase = 0.0;
649  throw CanteraError("MixtureFugacityTP::densityCalc()", "Process did not converge");
650  } else {
651  densBase = mmw / molarVolBase;
652  }
653  return densBase;
654 }
655 
656 void MixtureFugacityTP::updateMixingExpressions()
657 {
658 }
659 
660 MixtureFugacityTP::spinodalFunc::spinodalFunc(MixtureFugacityTP* tp) :
661  m_tp(tp)
662 {
663 }
664 
665 int MixtureFugacityTP::spinodalFunc::evalSS(const doublereal t, const doublereal* const y,
666  doublereal* const r)
667 {
668  doublereal molarVol = y[0];
669  doublereal pp;
670  r[0] = m_tp->dpdVCalc(m_tp->temperature(), molarVol, pp);
671  return 0;
672 }
673 
674 int MixtureFugacityTP::corr0(doublereal TKelvin, doublereal pres, doublereal& densLiqGuess,
675  doublereal& densGasGuess, doublereal& liqGRT, doublereal& gasGRT)
676 {
677 
678  int retn = 0;
679  doublereal densLiq = densityCalc(TKelvin, pres, FLUID_LIQUID_0, densLiqGuess);
680  if (densLiq <= 0.0) {
681  retn = -1;
682  } else {
683  densLiqGuess = densLiq;
684  setState_TR(TKelvin, densLiq);
685  liqGRT = gibbs_mole() / _RT();
686  }
687 
688  doublereal densGas = densityCalc(TKelvin, pres, FLUID_GAS, densGasGuess);
689  if (densGas <= 0.0) {
690  if (retn == -1) {
691  throw Cantera::CanteraError("MixtureFugacityTP::corr0",
692  "Error occurred trying to find gas density at (T,P) = "
693  + Cantera::fp2str(TKelvin) + " " + Cantera::fp2str(pres));
694  }
695  retn = -2;
696  } else {
697  densGasGuess = densGas;
698  setState_TR(TKelvin, densGas);
699  gasGRT = gibbs_mole() / _RT();
700  }
701  return retn;
702 }
703 
704 int MixtureFugacityTP::phaseState(bool checkState) const
705 {
706  int state = iState_;
707  if (checkState) {
708  double t = temperature();
709  double tcrit = critTemperature();
710  double rhocrit = critDensity();
711  if (t >= tcrit) {
712  return FLUID_SUPERCRIT;
713  }
714  double tmid = tcrit - 100.;
715  if (tmid < 0.0) {
716  tmid = tcrit / 2.0;
717  }
718  double pp = psatEst(tmid);
719  double mmw = meanMolecularWeight();
720  double molVolLiqTmid = liquidVolEst(tmid, pp);
721  double molVolGasTmid = GasConstant * tmid / (pp);
722  double densLiqTmid = mmw / molVolLiqTmid;
723  double densGasTmid = mmw / molVolGasTmid;
724  double densMidTmid = 0.5 * (densLiqTmid + densGasTmid);
725  doublereal rhoMid = rhocrit + (t - tcrit) * (rhocrit - densMidTmid) / (tcrit - tmid);
726 
727  double rho = density();
728  int iStateGuess = FLUID_LIQUID_0;
729  if (rho < rhoMid) {
730  iStateGuess = FLUID_GAS;
731  }
732  double molarVol = mmw / rho;
733  double presCalc;
734 
735  double dpdv = dpdVCalc(t, molarVol, presCalc);
736  if (dpdv < 0.0) {
737  state = iStateGuess;
738  } else {
739  state = FLUID_UNSTABLE;
740  }
741 
742  }
743  return state;
744 }
745 
747 {
748  throw CanteraError("MixtureFugacityTP::densSpinodalLiquid", "unimplemented");
749 }
750 
752 {
753  throw CanteraError("MixtureFugacityTP::densSpinodalGas", "unimplemented");
754 }
755 
756 doublereal MixtureFugacityTP::satPressure(doublereal TKelvin)
757 {
758  doublereal molarVolGas;
759  doublereal molarVolLiquid;
760  return calculatePsat(TKelvin, molarVolGas, molarVolLiquid);
761 }
762 
763 doublereal MixtureFugacityTP::calculatePsat(doublereal TKelvin, doublereal& molarVolGas,
764  doublereal& molarVolLiquid)
765 {
766  /*
767  * The algorithm for this routine has undergone quite a bit of work. It probably needs more work.
768  * However, it seems now to be fairly robust.
769  * The key requirement is to find an initial pressure where both the liquid and the gas exist. This
770  * is not as easy as it sounds, and it gets exceedingly hard as the critical temperature is approached
771  * from below.
772  * Once we have this initial state, then we seek to equilibrate the Gibbs free energies of the
773  * gas and liquid and use the formula
774  *
775  * dp = VdG
776  *
777  * to create an update condition for deltaP using
778  *
779  * - (Gliq - Ggas) = (Vliq - Vgas) (deltaP)
780  *
781  * @TODO Suggestions for the future would be to switch it to an algorithm that uses the gas molar volume
782  * and the liquid molar volumes as the fundamental unknowns.
783  */
784 
785  // we need this because this is a non-const routine that is public
786  setTemperature(TKelvin);
787  double densSave = density();
788  double tempSave = temperature();
789  double pres;
790  doublereal mw = meanMolecularWeight();
791  if (TKelvin < critTemperature()) {
792 
793  pres = psatEst(TKelvin);
794  // trial value = Psat from correlation
795  doublereal volLiquid = liquidVolEst(TKelvin, pres);
796  double RhoLiquidGood = mw / volLiquid;
797  double RhoGasGood = pres * mw / (GasConstant * TKelvin);
798  doublereal delGRT = 1.0E6;
799  doublereal liqGRT, gasGRT;
800 
801  /*
802  * First part of the calculation involves finding a pressure at which the
803  * gas and the liquid state coexists.
804  */
805  doublereal presLiquid = 0.;
806  doublereal presGas;
807  doublereal presBase = pres;
808  bool foundLiquid = false;
809  bool foundGas = false;
810 
811  doublereal densLiquid = densityCalc(TKelvin, presBase, FLUID_LIQUID_0, RhoLiquidGood);
812  if (densLiquid > 0.0) {
813  foundLiquid = true;
814  presLiquid = pres;
815  RhoLiquidGood = densLiquid;
816  }
817  if (!foundLiquid) {
818  for (int i = 0; i < 50; i++) {
819  pres = 1.1 * pres;
820  densLiquid = densityCalc(TKelvin, pres, FLUID_LIQUID_0, RhoLiquidGood);
821  if (densLiquid > 0.0) {
822  foundLiquid = true;
823  presLiquid = pres;
824  RhoLiquidGood = densLiquid;
825  break;
826  }
827  }
828  }
829 
830  pres = presBase;
831  doublereal densGas = densityCalc(TKelvin, pres, FLUID_GAS, RhoGasGood);
832  if (densGas <= 0.0) {
833  foundGas = false;
834  } else {
835  foundGas = true;
836  presGas = pres;
837  RhoGasGood = densGas;
838  }
839  if (!foundGas) {
840  for (int i = 0; i < 50; i++) {
841  pres = 0.9 * pres;
842  densGas = densityCalc(TKelvin, pres, FLUID_GAS, RhoGasGood);
843  if (densGas > 0.0) {
844  foundGas = true;
845  presGas = pres;
846  RhoGasGood = densGas;
847  break;
848  }
849  }
850  }
851 
852  if (foundGas && foundLiquid) {
853  if (presGas != presLiquid) {
854  pres = 0.5 * (presLiquid + presGas);
855  bool goodLiq;
856  bool goodGas;
857  for (int i = 0; i < 50; i++) {
858  densLiquid = densityCalc(TKelvin, pres, FLUID_LIQUID_0, RhoLiquidGood);
859  if (densLiquid <= 0.0) {
860  goodLiq = false;
861  } else {
862  goodLiq = true;
863  RhoLiquidGood = densLiquid;
864  presLiquid = pres;
865  }
866  densGas = densityCalc(TKelvin, pres, FLUID_GAS, RhoGasGood);
867  if (densGas <= 0.0) {
868  goodGas = false;
869  } else {
870  goodGas = true;
871  RhoGasGood = densGas;
872  presGas = pres;
873  }
874  if (goodGas && goodLiq) {
875  break;
876  }
877  if (!goodLiq && !goodGas) {
878  pres = 0.5 * (pres + presLiquid);
879  }
880  if (goodLiq || goodGas) {
881  pres = 0.5 * (presLiquid + presGas);
882  }
883  }
884  }
885  }
886  if (!foundGas || !foundLiquid) {
887  printf("error couldn't find a starting pressure\n");
888  return 0.0;
889  }
890  if (presGas != presLiquid) {
891  printf("error couldn't find a starting pressure\n");
892  return 0.0;
893  }
894 
895  pres = presGas;
896  double presLast = pres;
897  double RhoGas = RhoGasGood;
898  double RhoLiquid = RhoLiquidGood;
899 
900 
901  /*
902  * Now that we have found a good pressure we can proceed with the algorithm.
903  */
904 
905  for (int i = 0; i < 20; i++) {
906  int stab = corr0(TKelvin, pres, RhoLiquid, RhoGas, liqGRT, gasGRT);
907  if (stab == 0) {
908  presLast = pres;
909  delGRT = liqGRT - gasGRT;
910  doublereal delV = mw * (1.0/RhoLiquid - 1.0/RhoGas);
911  doublereal dp = - delGRT * GasConstant * TKelvin / delV;
912 
913  if (fabs(dp) > 0.1 * pres) {
914  if (dp > 0.0) {
915  dp = 0.1 * pres;
916  } else {
917  dp = -0.1 * pres;
918  }
919  }
920  pres += dp;
921 
922  } else if (stab == -1) {
923  delGRT = 1.0E6;
924  if (presLast > pres) {
925  pres = 0.5 * (presLast + pres);
926  } else {
927  // we are stuck here - try this
928  pres = 1.1 * pres;
929  }
930  } else if (stab == -2) {
931  if (presLast < pres) {
932  pres = 0.5 * (presLast + pres);
933  } else {
934  // we are stuck here - try this
935  pres = 0.9 * pres;
936  }
937  }
938  molarVolGas = mw / RhoGas;
939  molarVolLiquid = mw / RhoLiquid;
940 
941 
942  if (fabs(delGRT) < 1.0E-8) {
943  // converged
944  break;
945  }
946  }
947 
948  molarVolGas = mw / RhoGas;
949  molarVolLiquid = mw / RhoLiquid;
950  // Put the fluid in the desired end condition
951  setState_TR(tempSave, densSave);
952 
953  return pres;
954 
955 
956  } else {
957  pres = critPressure();
958  setState_TP(TKelvin, pres);
959  molarVolGas = mw / density();
960  molarVolLiquid = molarVolGas;
961  setState_TR(tempSave, densSave);
962  }
963  return pres;
964 }
965 
966 doublereal MixtureFugacityTP::pressureCalc(doublereal TKelvin, doublereal molarVol) const
967 {
968  throw CanteraError("MixtureFugacityTP::pressureCalc", "unimplemented");
969 }
970 
971 doublereal MixtureFugacityTP::dpdVCalc(doublereal TKelvin, doublereal molarVol, doublereal& presCalc) const
972 {
973  throw CanteraError("MixtureFugacityTP::dpdVCalc", "unimplemented");
974 }
975 
977 {
978  double Tnow = temperature();
979 
980  // If the temperature has changed since the last time these
981  // properties were computed, recompute them.
982  if (m_Tlast_ref != Tnow) {
983  m_spthermo->update(Tnow, &m_cp0_R[0], &m_h0_RT[0], &m_s0_R[0]);
984  m_Tlast_ref = Tnow;
985 
986  // update the species Gibbs functions
987  for (size_t k = 0; k < m_kk; k++) {
988  m_g0_RT[k] = m_h0_RT[k] - m_s0_R[k];
989  }
990  doublereal pref = refPressure();
991  if (pref <= 0.0) {
992  throw CanteraError("MixtureFugacityTP::_updateReferenceStateThermo()", "neg ref pressure");
993  }
994  m_logc0 = log(pref/(GasConstant * Tnow));
995  }
996 }
997 
998 }
virtual void setMoleFractions_NoNorm(const doublereal *const x)
Set the mole fractions to the specified values without normalizing.
Definition: Phase.cpp:367
virtual doublereal satPressure(doublereal TKelvin)
Calculate the saturation pressure at the current mixture content for the given temperature.
virtual void calcDensity()
Calculate the density of the mixture using the partial molar volumes and mole fractions as input...
virtual void setState_TPX(doublereal t, doublereal p, const doublereal *x)
Set the temperature (K), pressure (Pa), and mole fractions.
virtual doublereal densSpinodalGas() const
Return the value of the density at the gas spinodal point (on the gas side) for the current temperatu...
virtual doublereal density() const
Density (kg/m^3).
Definition: Phase.h:608
virtual void initThermoXML(XML_Node &phaseNode, const std::string &id)
Initialize a ThermoPhase object, potentially reading activity coefficient information from an XML dat...
virtual doublereal densityCalc(doublereal TKelvin, doublereal pressure, int phaseRequested, doublereal rhoguess)
Calculates the density given the temperature and the pressure and a guess at the density.
virtual doublereal liquidVolEst(doublereal TKelvin, doublereal &pres) const
Estimate for the molar volume of the liquid.
CTML ("Cantera Markup Language") is the variant of XML that Cantera uses to store data...
virtual doublereal gibbs_mole() const
Molar Gibbs function. Units: J/kmol.
Definition: ThermoPhase.h:242
std::string getChildValue(const XML_Node &parent, const std::string &nameString)
This function reads a child node with the name, nameString, and returns its XML value as the return s...
Definition: ctml.cpp:142
An error indicating that an unimplemented function has been called.
Definition: ctexceptions.h:213
virtual void getGibbs_ref(doublereal *g) const
doublereal _RT() const
Return the Gas Constant multiplied by the current temperature.
Definition: ThermoPhase.h:936
virtual void getStandardChemPotentials(doublereal *mu) const
Get the array of chemical potentials at unit activity.
virtual void initThermo()
Initialize the ThermoPhase object after all species have been set up.
ThermoPhase & operator=(const ThermoPhase &right)
Assignment operator.
Definition: ThermoPhase.cpp:60
int forcedState_
Force the system to be on a particular side of the spinodal curve.
void getPureGibbs(doublereal *gpure) const
Get the pure Gibbs free energies of each species.
doublereal z() const
Calculate the value of z.
virtual void getCp_R(doublereal *cpr) const
Get the nondimensional Heat Capacities at constant pressure for the standard state of the species at ...
const int cSS_CONVENTION_TEMPERATURE
Standard state uses the molar convention.
Definition: ThermoPhase.h:34
vector_fp m_g0_RT
Temporary storage for dimensionless reference state Gibbs energies.
virtual void setMoleFractions(const doublereal *const x)
Set the mole fractions to the specified values, and then normalize them so that they sum to 1...
Class XML_Node is a tree-based representation of the contents of an XML file.
Definition: xml.h:100
This is a filter class for ThermoPhase that implements some preparatory steps for efficiently handlin...
MixtureFugacityTP & operator=(const MixtureFugacityTP &b)
Assignment operator.
virtual int standardStateConvention() const
This method returns the convention used in specification of the standard state, of which there are cu...
doublereal calculatePsat(doublereal TKelvin, doublereal &molarVolGas, doublereal &molarVolLiquid)
Calculate the saturation pressure at the current mixture content for the given temperature.
virtual doublereal critTemperature() const
Critical temperature (K).
Definition: ThermoPhase.h:1227
virtual void getGibbs_RT_ref(doublereal *grt) const
Returns the vector of nondimensional Gibbs free energies of the reference state at the current temper...
void getMoleFractions(doublereal *const x) const
Get the species mole fraction vector.
Definition: Phase.cpp:556
doublereal pressure() const
Returns the current pressure of the phase.
virtual void getStandardVolumes_ref(doublereal *vol) const
Get the molar volumes of the species reference states at the current T and reference pressure of the ...
#define FLUID_UNSTABLE
Various states of the Fugacity object.
virtual void getEnthalpy_RT_ref(doublereal *hrt) const
Returns the vector of nondimensional enthalpies of the reference state at the current temperature of ...
virtual void getGibbs_RT(doublereal *grt) const
Get the nondimensional Gibbs functions for the species at their standard states of solution at the cu...
Base class for a phase with thermodynamic properties.
Definition: ThermoPhase.h:97
virtual void setState_TR(doublereal T, doublereal rho)
Set the internally stored temperature (K) and density (kg/m^3)
vector_fp m_s0_R
Temporary storage for dimensionless reference state entropies.
virtual void getStandardVolumes(doublereal *vol) const
Get the molar volumes of each species in their standard states at the current T and P of the solution...
doublereal m_Pcurrent
Current value of the pressures.
virtual void setMassFractions_NoNorm(const doublereal *const y)
Set the mass fractions to the specified values without normalizing.
virtual void setMassFractions(const doublereal *const y)
Set the mass fractions to the specified values, and then normalize them so that they sum to 1...
virtual void setTemperature(const doublereal temp)
Set the temperature of the phase.
virtual doublereal psatEst(doublereal TKelvin) const
Estimate for the saturation pressure.
virtual doublereal densSpinodalLiquid() const
Return the value of the density at the liquid spinodal point (on the liquid side) for the current tem...
virtual doublereal critDensity() const
Critical density (kg/m3).
Definition: ThermoPhase.h:1247
Header file for a derived class of ThermoPhase that handles non-ideal mixtures based on the fugacity ...
doublereal molarVolume() const
Molar volume (m^3/kmol).
Definition: Phase.cpp:673
virtual void setConcentrations(const doublereal *const c)
Set the concentrations to the specified values within the phase.
void modifyOneHf298SS(const size_t k, const doublereal Hf298New)
Modify the value of the 298 K Heat of Formation of the standard state of one species in the phase (J ...
std::string fp2str(const double x, const std::string &fmt)
Convert a double into a c++ string.
Definition: stringUtils.cpp:28
doublereal m_logc0
Temporary storage for log of p/rt.
virtual void getChemPotentials(doublereal *mu) const
Get the species chemical potentials. Units: J/kmol.
Definition: ThermoPhase.h:554
void setMoleFractionsByName(const compositionMap &xMap)
Set the species mole fractions by name.
Definition: Phase.cpp:376
const vector_fp & gibbs_RT_ref() const
Returns the vector of nondimensional Gibbs free energies of the reference state at the current temper...
std::vector< doublereal > moleFractions_
Storage for the current values of the mole fractions of the species.
virtual doublereal refPressure(size_t k=npos) const =0
The reference-state pressure for species k.
void setMassFractionsByName(const compositionMap &yMap)
Set the species mass fractions by name.
Definition: Phase.cpp:415
virtual doublereal pressureCalc(doublereal TKelvin, doublereal molarVol) const
Calculate the pressure given the temperature and the molar volume.
Base class for exceptions thrown by Cantera classes.
Definition: ctexceptions.h:99
virtual void setConcentrations(const doublereal *const conc)
Set the concentrations to the specified values within the phase.
Definition: Phase.cpp:614
virtual void setMoleFractions(const doublereal *const x)
Set the mole fractions to the specified values There is no restriction on the sum of the mole fractio...
Definition: Phase.cpp:331
void getChemPotentials_RT(doublereal *mu) const
Get the array of non-dimensional species chemical potentials These are partial molar Gibbs free energ...
bool hasChild(const std::string &ch) const
Tests whether the current node has a child node with a particular name.
Definition: xml.cpp:563
virtual doublereal hresid() const
Calculate the deviation terms for the total enthalpy of the mixture from the ideal gas mixture...
virtual void setForcedSolutionBranch(int solnBranch)
Set the solution branch to force the ThermoPhase to exist on one branch or another.
int phaseState(bool checkState=false) const
Returns the Phase State flag for the current state of the object.
virtual int forcedSolutionBranch() const
Report the solution branch which the solution is restricted to.
virtual void setPressure(doublereal p)
Set the internally stored pressure (Pa) at constant temperature and composition.
virtual void getIntEnergy_RT(doublereal *urt) const
Returns the vector of nondimensional internal Energies of the standard state at the current temperatu...
virtual void setMoleFractions_NoNorm(const doublereal *const x)
Set the mole fractions to the specified values without normalizing.
virtual doublereal refPressure() const
Returns the reference pressure in Pa.
Definition: ThermoPhase.h:150
virtual void setMassFractions_NoNorm(const doublereal *const y)
Set the mass fractions to the specified values without normalizing.
Definition: Phase.cpp:404
virtual void getEntropy_R(doublereal *sr) const
Get the array of nondimensional Enthalpy functions for the standard state species.
virtual doublereal critPressure() const
Critical pressure (Pa).
Definition: ThermoPhase.h:1232
doublereal temperature() const
Temperature (K).
Definition: Phase.h:602
virtual ThermoPhase * duplMyselfAsThermoPhase() const
Duplication routine.
virtual void initThermoXML(XML_Node &phaseNode, const std::string &id)
Import and initialize a ThermoPhase object using an XML tree.
int iState_
Current state of the fluid.
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
Templates for operations on vector-like objects.
virtual void setTemperature(const doublereal temp)
Set the internally stored temperature of the phase (K).
Definition: Phase.h:638
void scale(InputIter begin, InputIter end, OutputIter out, S scale_factor)
Multiply elements of an array by a scale factor.
Definition: utilities.h:158
doublereal m_Tlast_ref
The last temperature at which the reference state thermodynamic properties were calculated at...
doublereal meanMolecularWeight() const
The mean molecular weight. Units: (kg/kmol)
Definition: Phase.h:669
const doublereal GasConstant
Universal Gas Constant. [J/kmol/K].
Definition: ct_defs.h:64
Contains declarations for string manipulation functions within Cantera.
int corr0(doublereal TKelvin, doublereal pres, doublereal &densLiq, doublereal &densGas, doublereal &liqGRT, doublereal &gasGRT)
Utility routine in the calculation of the saturation pressure.
doublereal getFloat(const XML_Node &parent, const std::string &name, const std::string &type)
Get a floating-point value from a child element.
Definition: ctml.cpp:194
virtual void modifyOneHf298(const size_t k, const doublereal Hf298New)=0
Modify the value of the 298 K Heat of Formation of the standard state of one species in the phase (J ...
#define DATA_PTR(vec)
Creates a pointer to the start of the raw data for a vector.
Definition: ct_defs.h:36
virtual void setMassFractions(const doublereal *const y)
Set the mass fractions to the specified values and normalize them.
Definition: Phase.cpp:390
size_t m_kk
Number of species in the phase.
Definition: Phase.h:843
virtual void setState_TP(doublereal T, doublereal pres)
Set the temperature and pressure at the same time.
virtual void getEntropy_R_ref(doublereal *er) const
virtual void update(doublereal T, doublereal *cp_R, doublereal *h_RT, doublereal *s_R) const =0
Compute the reference-state properties for all species.
virtual doublereal sresid() const
Calculate the deviation terms for the total entropy of the mixture from the ideal gas mixture...
virtual void _updateReferenceStateThermo() const
Updates the reference state thermodynamic functions at the current T of the solution.
virtual int reportSolnBranchActual() const
Report the solution branch which the solution is actually on.
SpeciesThermo * m_spthermo
Pointer to the calculation manager for species reference-state thermodynamic properties.
Definition: ThermoPhase.h:1607
virtual void getCp_R_ref(doublereal *cprt) const
virtual void getEnthalpy_RT(doublereal *hrt) const
Get the nondimensional Enthalpy functions for the species at their standard states at the current T a...
virtual void setDensity(const doublereal density_)
Set the internally stored density (kg/m^3) of the phase Note the density of a phase is an independent...
Definition: Phase.h:623
vector_fp m_h0_RT
Temporary storage for dimensionless reference state enthalpies.
vector_fp m_cp0_R
Temporary storage for dimensionless reference state heat capacities.
virtual doublereal dpdVCalc(doublereal TKelvin, doublereal molarVol, doublereal &presCalc) const
Calculate the pressure and the pressure derivative given the temperature and the molar volume...
virtual void setStateFromXML(const XML_Node &state)
Set the initial state of the phase to the conditions specified in the state XML element.