Cantera  2.5.1
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 // This file is part of Cantera. See License.txt in the top-level directory or
9 // at https://cantera.org/license.txt for license and copyright information.
10 
13 #include "cantera/base/ctml.h"
14 
15 using namespace std;
16 
17 namespace Cantera
18 {
19 
20 MixtureFugacityTP::MixtureFugacityTP() :
21  iState_(FLUID_GAS),
22  forcedState_(FLUID_UNDEFINED),
23  m_Tlast_ref(-1.0)
24 {
25 }
26 
28 {
30 }
31 
33 {
34  forcedState_ = solnBranch;
35 }
36 
38 {
39  return forcedState_;
40 }
41 
43 {
44  return iState_;
45 }
46 
47 // ---- Partial Molar Properties of the Solution -----------------
48 
49 void MixtureFugacityTP::getChemPotentials_RT(doublereal* muRT) const
50 {
51  getChemPotentials(muRT);
52  for (size_t k = 0; k < m_kk; k++) {
53  muRT[k] *= 1.0 / RT();
54  }
55 }
56 
57 // ----- Thermodynamic Values for the Species Standard States States ----
58 
60 {
62  copy(m_g0_RT.begin(), m_g0_RT.end(), g);
63  double tmp = log(pressure() / refPressure());
64  for (size_t k = 0; k < m_kk; k++) {
65  g[k] = RT() * (g[k] + tmp);
66  }
67 }
68 
69 void MixtureFugacityTP::getEnthalpy_RT(doublereal* hrt) const
70 {
71  getEnthalpy_RT_ref(hrt);
72 }
73 
74 void MixtureFugacityTP::getEntropy_R(doublereal* sr) const
75 {
77  copy(m_s0_R.begin(), m_s0_R.end(), sr);
78  double tmp = log(pressure() / refPressure());
79  for (size_t k = 0; k < m_kk; k++) {
80  sr[k] -= tmp;
81  }
82 }
83 
84 void MixtureFugacityTP::getGibbs_RT(doublereal* grt) const
85 {
87  copy(m_g0_RT.begin(), m_g0_RT.end(), grt);
88  double tmp = log(pressure() / refPressure());
89  for (size_t k = 0; k < m_kk; k++) {
90  grt[k] += tmp;
91  }
92 }
93 
94 void MixtureFugacityTP::getPureGibbs(doublereal* g) const
95 {
97  scale(m_g0_RT.begin(), m_g0_RT.end(), g, RT());
98  double tmp = log(pressure() / refPressure()) * RT();
99  for (size_t k = 0; k < m_kk; k++) {
100  g[k] += tmp;
101  }
102 }
103 
104 void MixtureFugacityTP::getIntEnergy_RT(doublereal* urt) const
105 {
107  copy(m_h0_RT.begin(), m_h0_RT.end(), urt);
108  for (size_t i = 0; i < m_kk; i++) {
109  urt[i] -= 1.0;
110  }
111 }
112 
113 void MixtureFugacityTP::getCp_R(doublereal* cpr) const
114 {
116  copy(m_cp0_R.begin(), m_cp0_R.end(), cpr);
117 }
118 
119 void MixtureFugacityTP::getStandardVolumes(doublereal* vol) const
120 {
122  for (size_t i = 0; i < m_kk; i++) {
123  vol[i] = RT() / pressure();
124  }
125 }
126 
127 // ----- Thermodynamic Values for the Species Reference States ----
128 
129 void MixtureFugacityTP::getEnthalpy_RT_ref(doublereal* hrt) const
130 {
132  copy(m_h0_RT.begin(), m_h0_RT.end(), hrt);
133 }
134 
135 void MixtureFugacityTP::getGibbs_RT_ref(doublereal* grt) const
136 {
138  copy(m_g0_RT.begin(), m_g0_RT.end(), grt);
139 }
140 
141 void MixtureFugacityTP::getGibbs_ref(doublereal* g) const
142 {
143  const vector_fp& gibbsrt = gibbs_RT_ref();
144  scale(gibbsrt.begin(), gibbsrt.end(), g, RT());
145 }
146 
148 {
150  return m_g0_RT;
151 }
152 
153 void MixtureFugacityTP::getEntropy_R_ref(doublereal* er) const
154 {
156  copy(m_s0_R.begin(), m_s0_R.end(), er);
157 }
158 
159 void MixtureFugacityTP::getCp_R_ref(doublereal* cpr) const
160 {
162  copy(m_cp0_R.begin(), m_cp0_R.end(), cpr);
163 }
164 
165 void MixtureFugacityTP::getStandardVolumes_ref(doublereal* vol) const
166 {
168  for (size_t i = 0; i < m_kk; i++) {
169  vol[i]= RT() / refPressure();
170  }
171 }
172 
174 {
175  int doTP = 0;
176  string comp = getChildValue(state,"moleFractions");
177  if (comp != "") {
178  // not overloaded in current object -> phase state is not calculated.
180  doTP = 1;
181  } else {
182  comp = getChildValue(state,"massFractions");
183  if (comp != "") {
184  // not overloaded in current object -> phase state is not calculated.
186  doTP = 1;
187  }
188  }
189  double t = temperature();
190  if (state.hasChild("temperature")) {
191  t = getFloat(state, "temperature", "temperature");
192  doTP = 1;
193  }
194  if (state.hasChild("pressure")) {
195  double p = getFloat(state, "pressure", "pressure");
196  setState_TP(t, p);
197  } else if (state.hasChild("density")) {
198  double rho = getFloat(state, "density", "density");
199  setState_TR(t, rho);
200  } else if (doTP) {
201  double rho = Phase::density();
202  setState_TR(t, rho);
203  }
204 }
205 
206 bool MixtureFugacityTP::addSpecies(shared_ptr<Species> spec)
207 {
208  bool added = ThermoPhase::addSpecies(spec);
209  if (added) {
210  if (m_kk == 1) {
211  moleFractions_.push_back(1.0);
212  } else {
213  moleFractions_.push_back(0.0);
214  }
215  m_h0_RT.push_back(0.0);
216  m_cp0_R.push_back(0.0);
217  m_g0_RT.push_back(0.0);
218  m_s0_R.push_back(0.0);
219  }
220  return added;
221 }
222 
223 void MixtureFugacityTP::setTemperature(const doublereal temp)
224 {
226  setState_TR(temperature(), density());
227 }
228 
230 {
231  setState_TP(temperature(), p);
232  }
233 
235 {
238 }
239 
240 void MixtureFugacityTP::setMoleFractions_NoState(const doublereal* const x)
241 {
244  updateMixingExpressions();
245 }
246 
248 {
249  throw NotImplementedError("MixtureFugacityTP::calcDensity");
250 }
251 
252 void MixtureFugacityTP::setState_TP(doublereal t, doublereal pres)
253 {
254  // A pretty tricky algorithm is needed here, due to problems involving
255  // standard states of real fluids. For those cases you need to combine the T
256  // and P specification for the standard state, or else you may venture into
257  // the forbidden zone, especially when nearing the triple point. Therefore,
258  // we need to do the standard state thermo calc with the (t, pres) combo.
260 
263  // Depends on the mole fractions and the temperature
264  updateMixingExpressions();
265 
266  if (forcedState_ == FLUID_UNDEFINED) {
267  double rhoNow = Phase::density();
268  double rho = densityCalc(t, pres, iState_, rhoNow);
269  if (rho > 0.0) {
270  Phase::setDensity(rho);
271  iState_ = phaseState(true);
272  } else {
273  if (rho < -1.5) {
274  rho = densityCalc(t, pres, FLUID_UNDEFINED , rhoNow);
275  if (rho > 0.0) {
276  Phase::setDensity(rho);
277  iState_ = phaseState(true);
278  } else {
279  throw CanteraError("MixtureFugacityTP::setState_TP", "neg rho");
280  }
281  } else {
282  throw CanteraError("MixtureFugacityTP::setState_TP", "neg rho");
283  }
284  }
285  } else if (forcedState_ == FLUID_GAS) {
286  // Normal density calculation
287  if (iState_ < FLUID_LIQUID_0) {
288  double rhoNow = Phase::density();
289  double rho = densityCalc(t, pres, iState_, rhoNow);
290  if (rho > 0.0) {
291  Phase::setDensity(rho);
292  iState_ = phaseState(true);
293  if (iState_ >= FLUID_LIQUID_0) {
294  throw CanteraError("MixtureFugacityTP::setState_TP", "wrong state");
295  }
296  } else {
297  throw CanteraError("MixtureFugacityTP::setState_TP", "neg rho");
298  }
299  }
300  } else if (forcedState_ > FLUID_LIQUID_0) {
301  if (iState_ >= FLUID_LIQUID_0) {
302  double rhoNow = Phase::density();
303  double rho = densityCalc(t, pres, iState_, rhoNow);
304  if (rho > 0.0) {
305  Phase::setDensity(rho);
306  iState_ = phaseState(true);
307  if (iState_ == FLUID_GAS) {
308  throw CanteraError("MixtureFugacityTP::setState_TP", "wrong state");
309  }
310  } else {
311  throw CanteraError("MixtureFugacityTP::setState_TP", "neg rho");
312  }
313  }
314  }
315 }
316 
317 void MixtureFugacityTP::setState_TR(doublereal T, doublereal rho)
318 {
322  Phase::setDensity(rho);
323  // depends on mole fraction and temperature
324  updateMixingExpressions();
325  iState_ = phaseState(true);
326 }
327 
328 void MixtureFugacityTP::setState_TPX(doublereal t, doublereal p, const doublereal* x)
329 {
330  setMoleFractions_NoState(x);
331  setState_TP(t,p);
332 }
333 
334 doublereal MixtureFugacityTP::z() const
335 {
336  return pressure() * meanMolecularWeight() / (density() * RT());
337 }
338 
339 doublereal MixtureFugacityTP::sresid() const
340 {
341  throw NotImplementedError("MixtureFugacityTP::sresid");
342 }
343 
344 doublereal MixtureFugacityTP::hresid() const
345 {
346  throw NotImplementedError("MixtureFugacityTP::hresid");
347 }
348 
349 doublereal MixtureFugacityTP::psatEst(doublereal TKelvin) const
350 {
351  doublereal pcrit = critPressure();
352  doublereal tt = critTemperature() / TKelvin;
353  if (tt < 1.0) {
354  return pcrit;
355  }
356  doublereal lpr = -0.8734*tt*tt - 3.4522*tt + 4.2918;
357  return pcrit*exp(lpr);
358 }
359 
360 doublereal MixtureFugacityTP::liquidVolEst(doublereal TKelvin, doublereal& pres) const
361 {
362  throw NotImplementedError("MixtureFugacityTP::liquidVolEst");
363 }
364 
365 doublereal MixtureFugacityTP::densityCalc(doublereal TKelvin, doublereal presPa,
366  int phase, doublereal rhoguess)
367 {
368  doublereal tcrit = critTemperature();
369  doublereal mmw = meanMolecularWeight();
370  if (rhoguess == -1.0) {
371  if (phase != -1) {
372  if (TKelvin > tcrit) {
373  rhoguess = presPa * mmw / (GasConstant * TKelvin);
374  } else {
375  if (phase == FLUID_GAS || phase == FLUID_SUPERCRIT) {
376  rhoguess = presPa * mmw / (GasConstant * TKelvin);
377  } else if (phase >= FLUID_LIQUID_0) {
378  double lqvol = liquidVolEst(TKelvin, presPa);
379  rhoguess = mmw / lqvol;
380  }
381  }
382  } else {
383  // Assume the Gas phase initial guess, if nothing is specified to
384  // the routine
385  rhoguess = presPa * mmw / (GasConstant * TKelvin);
386  }
387  }
388 
389  double molarVolBase = mmw / rhoguess;
390  double molarVolLast = molarVolBase;
391  double vc = mmw / critDensity();
392 
393  // molar volume of the spinodal at the current temperature and mole
394  // fractions. this will be updated as we go.
395  double molarVolSpinodal = vc;
396  bool conv = false;
397 
398  // We start on one side of the vc and stick with that side
399  bool gasSide = molarVolBase > vc;
400  if (gasSide) {
401  molarVolLast = (GasConstant * TKelvin)/presPa;
402  } else {
403  molarVolLast = liquidVolEst(TKelvin, presPa);
404  }
405 
406  // OK, now we do a small solve to calculate the molar volume given the T,P
407  // value. The algorithm is taken from dfind()
408  for (int n = 0; n < 200; n++) {
409  // Calculate the predicted reduced pressure, pred0, based on the current
410  // tau and dd. Calculate the derivative of the predicted pressure wrt
411  // the molar volume. This routine also returns the pressure, presBase
412  double presBase;
413  double dpdVBase = dpdVCalc(TKelvin, molarVolBase, presBase);
414 
415  // If dpdV is positive, then we are in the middle of the 2 phase region
416  // and beyond the spinodal stability curve. We need to adjust the
417  // initial guess outwards and start a new iteration.
418  if (dpdVBase >= 0.0) {
419  if (TKelvin > tcrit) {
420  throw CanteraError("MixtureFugacityTP::densityCalc",
421  "T > tcrit unexpectedly");
422  }
423 
424  // TODO Spawn a calculation for the value of the spinodal point that
425  // is very accurate. Answer the question as to whether a
426  // solution is possible on the current side of the vapor dome.
427  if (gasSide) {
428  if (molarVolBase >= vc) {
429  molarVolSpinodal = molarVolBase;
430  molarVolBase = 0.5 * (molarVolLast + molarVolSpinodal);
431  } else {
432  molarVolBase = 0.5 * (molarVolLast + molarVolSpinodal);
433  }
434  } else {
435  if (molarVolBase <= vc) {
436  molarVolSpinodal = molarVolBase;
437  molarVolBase = 0.5 * (molarVolLast + molarVolSpinodal);
438  } else {
439  molarVolBase = 0.5 * (molarVolLast + molarVolSpinodal);
440  }
441  }
442  continue;
443  }
444 
445  // Check for convergence
446  if (fabs(presBase-presPa) < 1.0E-30 + 1.0E-8 * presPa) {
447  conv = true;
448  break;
449  }
450 
451  // Dampen and crop the update
452  doublereal dpdV = dpdVBase;
453  if (n < 10) {
454  dpdV = dpdVBase * 1.5;
455  }
456 
457  // Formulate the update to the molar volume by Newton's method. Then,
458  // crop it to a max value of 0.1 times the current volume
459  double delMV = - (presBase - presPa) / dpdV;
460  if ((!gasSide || delMV < 0.0) && fabs(delMV) > 0.2 * molarVolBase) {
461  delMV = delMV / fabs(delMV) * 0.2 * molarVolBase;
462  }
463  // Only go 1/10 the way towards the spinodal at any one time.
464  if (TKelvin < tcrit) {
465  if (gasSide) {
466  if (delMV < 0.0 && -delMV > 0.5 * (molarVolBase - molarVolSpinodal)) {
467  delMV = - 0.5 * (molarVolBase - molarVolSpinodal);
468  }
469  } else {
470  if (delMV > 0.0 && delMV > 0.5 * (molarVolSpinodal - molarVolBase)) {
471  delMV = 0.5 * (molarVolSpinodal - molarVolBase);
472  }
473  }
474  }
475  // updated the molar volume value
476  molarVolLast = molarVolBase;
477  molarVolBase += delMV;
478 
479  if (fabs(delMV/molarVolBase) < 1.0E-14) {
480  conv = true;
481  break;
482  }
483 
484  // Check for negative molar volumes
485  if (molarVolBase <= 0.0) {
486  molarVolBase = std::min(1.0E-30, fabs(delMV*1.0E-4));
487  }
488  }
489 
490  // Check for convergence, and return 0.0 if it wasn't achieved.
491  double densBase = 0.0;
492  if (! conv) {
493  molarVolBase = 0.0;
494  throw CanteraError("MixtureFugacityTP::densityCalc", "Process did not converge");
495  } else {
496  densBase = mmw / molarVolBase;
497  }
498  return densBase;
499 }
500 
501 void MixtureFugacityTP::updateMixingExpressions()
502 {
503 }
504 
505 int MixtureFugacityTP::corr0(doublereal TKelvin, doublereal pres, doublereal& densLiqGuess,
506  doublereal& densGasGuess, doublereal& liqGRT, doublereal& gasGRT)
507 {
508  int retn = 0;
509  doublereal densLiq = densityCalc(TKelvin, pres, FLUID_LIQUID_0, densLiqGuess);
510  if (densLiq <= 0.0) {
511  retn = -1;
512  } else {
513  densLiqGuess = densLiq;
514  setState_TR(TKelvin, densLiq);
515  liqGRT = gibbs_mole() / RT();
516  }
517 
518  doublereal densGas = densityCalc(TKelvin, pres, FLUID_GAS, densGasGuess);
519  if (densGas <= 0.0) {
520  if (retn == -1) {
521  throw CanteraError("MixtureFugacityTP::corr0",
522  "Error occurred trying to find gas density at (T,P) = {} {}",
523  TKelvin, pres);
524  }
525  retn = -2;
526  } else {
527  densGasGuess = densGas;
528  setState_TR(TKelvin, densGas);
529  gasGRT = gibbs_mole() / RT();
530  }
531  return retn;
532 }
533 
534 int MixtureFugacityTP::phaseState(bool checkState) const
535 {
536  int state = iState_;
537  if (checkState) {
538  double t = temperature();
539  double tcrit = critTemperature();
540  double rhocrit = critDensity();
541  if (t >= tcrit) {
542  return FLUID_SUPERCRIT;
543  }
544  double tmid = tcrit - 100.;
545  if (tmid < 0.0) {
546  tmid = tcrit / 2.0;
547  }
548  double pp = psatEst(tmid);
549  double mmw = meanMolecularWeight();
550  double molVolLiqTmid = liquidVolEst(tmid, pp);
551  double molVolGasTmid = GasConstant * tmid / pp;
552  double densLiqTmid = mmw / molVolLiqTmid;
553  double densGasTmid = mmw / molVolGasTmid;
554  double densMidTmid = 0.5 * (densLiqTmid + densGasTmid);
555  doublereal rhoMid = rhocrit + (t - tcrit) * (rhocrit - densMidTmid) / (tcrit - tmid);
556 
557  double rho = density();
558  int iStateGuess = FLUID_LIQUID_0;
559  if (rho < rhoMid) {
560  iStateGuess = FLUID_GAS;
561  }
562  double molarVol = mmw / rho;
563  double presCalc;
564 
565  double dpdv = dpdVCalc(t, molarVol, presCalc);
566  if (dpdv < 0.0) {
567  state = iStateGuess;
568  } else {
569  state = FLUID_UNSTABLE;
570  }
571  }
572  return state;
573 }
574 
576 {
577  throw NotImplementedError("MixtureFugacityTP::densSpinodalLiquid");
578 }
579 
581 {
582  throw NotImplementedError("MixtureFugacityTP::densSpinodalGas");
583 }
584 
585 doublereal MixtureFugacityTP::satPressure(doublereal TKelvin)
586 {
587  doublereal molarVolGas;
588  doublereal molarVolLiquid;
589  return calculatePsat(TKelvin, molarVolGas, molarVolLiquid);
590 }
591 
592 doublereal MixtureFugacityTP::calculatePsat(doublereal TKelvin, doublereal& molarVolGas,
593  doublereal& molarVolLiquid)
594 {
595  // The algorithm for this routine has undergone quite a bit of work. It
596  // probably needs more work. However, it seems now to be fairly robust. The
597  // key requirement is to find an initial pressure where both the liquid and
598  // the gas exist. This is not as easy as it sounds, and it gets exceedingly
599  // hard as the critical temperature is approached from below. Once we have
600  // this initial state, then we seek to equilibrate the Gibbs free energies
601  // of the gas and liquid and use the formula
602  //
603  // dp = VdG
604  //
605  // to create an update condition for deltaP using
606  //
607  // - (Gliq - Ggas) = (Vliq - Vgas) (deltaP)
608  //
609  // @TODO Suggestions for the future would be to switch it to an algorithm
610  // that uses the gas molar volume and the liquid molar volumes as the
611  // fundamental unknowns.
612 
613  // we need this because this is a non-const routine that is public
614  setTemperature(TKelvin);
615  double densSave = density();
616  double tempSave = temperature();
617  double pres;
618  doublereal mw = meanMolecularWeight();
619  if (TKelvin < critTemperature()) {
620  pres = psatEst(TKelvin);
621  // trial value = Psat from correlation
622  doublereal volLiquid = liquidVolEst(TKelvin, pres);
623  double RhoLiquidGood = mw / volLiquid;
624  double RhoGasGood = pres * mw / (GasConstant * TKelvin);
625  doublereal delGRT = 1.0E6;
626  doublereal liqGRT, gasGRT;
627 
628  // First part of the calculation involves finding a pressure at which
629  // the gas and the liquid state coexists.
630  doublereal presLiquid = 0.;
631  doublereal presGas;
632  doublereal presBase = pres;
633  bool foundLiquid = false;
634  bool foundGas = false;
635 
636  doublereal densLiquid = densityCalc(TKelvin, presBase, FLUID_LIQUID_0, RhoLiquidGood);
637  if (densLiquid > 0.0) {
638  foundLiquid = true;
639  presLiquid = pres;
640  RhoLiquidGood = densLiquid;
641  }
642  if (!foundLiquid) {
643  for (int i = 0; i < 50; i++) {
644  pres = 1.1 * pres;
645  densLiquid = densityCalc(TKelvin, pres, FLUID_LIQUID_0, RhoLiquidGood);
646  if (densLiquid > 0.0) {
647  foundLiquid = true;
648  presLiquid = pres;
649  RhoLiquidGood = densLiquid;
650  break;
651  }
652  }
653  }
654 
655  pres = presBase;
656  doublereal densGas = densityCalc(TKelvin, pres, FLUID_GAS, RhoGasGood);
657  if (densGas <= 0.0) {
658  foundGas = false;
659  } else {
660  foundGas = true;
661  presGas = pres;
662  RhoGasGood = densGas;
663  }
664  if (!foundGas) {
665  for (int i = 0; i < 50; i++) {
666  pres = 0.9 * pres;
667  densGas = densityCalc(TKelvin, pres, FLUID_GAS, RhoGasGood);
668  if (densGas > 0.0) {
669  foundGas = true;
670  presGas = pres;
671  RhoGasGood = densGas;
672  break;
673  }
674  }
675  }
676 
677  if (foundGas && foundLiquid && presGas != presLiquid) {
678  pres = 0.5 * (presLiquid + presGas);
679  bool goodLiq;
680  bool goodGas;
681  for (int i = 0; i < 50; i++) {
682  densLiquid = densityCalc(TKelvin, pres, FLUID_LIQUID_0, RhoLiquidGood);
683  if (densLiquid <= 0.0) {
684  goodLiq = false;
685  } else {
686  goodLiq = true;
687  RhoLiquidGood = densLiquid;
688  presLiquid = pres;
689  }
690  densGas = densityCalc(TKelvin, pres, FLUID_GAS, RhoGasGood);
691  if (densGas <= 0.0) {
692  goodGas = false;
693  } else {
694  goodGas = true;
695  RhoGasGood = densGas;
696  presGas = pres;
697  }
698  if (goodGas && goodLiq) {
699  break;
700  }
701  if (!goodLiq && !goodGas) {
702  pres = 0.5 * (pres + presLiquid);
703  }
704  if (goodLiq || goodGas) {
705  pres = 0.5 * (presLiquid + presGas);
706  }
707  }
708  }
709  if (!foundGas || !foundLiquid) {
710  warn_user("MixtureFugacityTP::calculatePsat",
711  "could not find a starting pressure; exiting.");
712  return 0.0;
713  }
714  if (presGas != presLiquid) {
715  warn_user("MixtureFugacityTP::calculatePsat",
716  "could not find a starting pressure; exiting");
717  return 0.0;
718  }
719 
720  pres = presGas;
721  double presLast = pres;
722  double RhoGas = RhoGasGood;
723  double RhoLiquid = RhoLiquidGood;
724 
725  // Now that we have found a good pressure we can proceed with the algorithm.
726  for (int i = 0; i < 20; i++) {
727  int stab = corr0(TKelvin, pres, RhoLiquid, RhoGas, liqGRT, gasGRT);
728  if (stab == 0) {
729  presLast = pres;
730  delGRT = liqGRT - gasGRT;
731  doublereal delV = mw * (1.0/RhoLiquid - 1.0/RhoGas);
732  doublereal dp = - delGRT * GasConstant * TKelvin / delV;
733 
734  if (fabs(dp) > 0.1 * pres) {
735  if (dp > 0.0) {
736  dp = 0.1 * pres;
737  } else {
738  dp = -0.1 * pres;
739  }
740  }
741  pres += dp;
742  } else if (stab == -1) {
743  delGRT = 1.0E6;
744  if (presLast > pres) {
745  pres = 0.5 * (presLast + pres);
746  } else {
747  // we are stuck here - try this
748  pres = 1.1 * pres;
749  }
750  } else if (stab == -2) {
751  if (presLast < pres) {
752  pres = 0.5 * (presLast + pres);
753  } else {
754  // we are stuck here - try this
755  pres = 0.9 * pres;
756  }
757  }
758  molarVolGas = mw / RhoGas;
759  molarVolLiquid = mw / RhoLiquid;
760 
761  if (fabs(delGRT) < 1.0E-8) {
762  // converged
763  break;
764  }
765  }
766 
767  molarVolGas = mw / RhoGas;
768  molarVolLiquid = mw / RhoLiquid;
769  // Put the fluid in the desired end condition
770  setState_TR(tempSave, densSave);
771  return pres;
772  } else {
773  pres = critPressure();
774  setState_TP(TKelvin, pres);
775  molarVolGas = mw / density();
776  molarVolLiquid = molarVolGas;
777  setState_TR(tempSave, densSave);
778  }
779  return pres;
780 }
781 
782 doublereal MixtureFugacityTP::pressureCalc(doublereal TKelvin, doublereal molarVol) const
783 {
784  throw NotImplementedError("MixtureFugacityTP::pressureCalc");
785 }
786 
787 doublereal MixtureFugacityTP::dpdVCalc(doublereal TKelvin, doublereal molarVol, doublereal& presCalc) const
788 {
789  throw NotImplementedError("MixtureFugacityTP::dpdVCalc");
790 }
791 
793 {
794  double Tnow = temperature();
795 
796  // If the temperature has changed since the last time these
797  // properties were computed, recompute them.
798  if (m_Tlast_ref != Tnow) {
799  m_spthermo.update(Tnow, &m_cp0_R[0], &m_h0_RT[0], &m_s0_R[0]);
800  m_Tlast_ref = Tnow;
801 
802  // update the species Gibbs functions
803  for (size_t k = 0; k < m_kk; k++) {
804  m_g0_RT[k] = m_h0_RT[k] - m_s0_R[k];
805  }
806  doublereal pref = refPressure();
807  if (pref <= 0.0) {
808  throw CanteraError("MixtureFugacityTP::_updateReferenceStateThermo", "neg ref pressure");
809  }
810  }
811 }
812 
814 {
816  m_Tlast_ref += 0.001234;
817 }
818 
819 }
Header file for a derived class of ThermoPhase that handles non-ideal mixtures based on the fugacity ...
#define FLUID_UNSTABLE
Various states of the Fugacity object.
Base class for exceptions thrown by Cantera classes.
Definition: ctexceptions.h:61
virtual void setStateFromXML(const XML_Node &state)
Set the initial state of the phase to the conditions specified in the state XML element.
int iState_
Current state of the fluid.
vector_fp m_g0_RT
Temporary storage for dimensionless reference state Gibbs energies.
virtual int reportSolnBranchActual() const
Report the solution branch which the solution is actually on.
vector_fp m_cp0_R
Temporary storage for dimensionless reference state heat capacities.
virtual bool addSpecies(shared_ptr< Species > spec)
virtual void getGibbs_RT_ref(doublereal *grt) const
Returns the vector of nondimensional Gibbs Free Energies of the reference state at the current temper...
virtual void getGibbs_RT(doublereal *grt) const
Get the nondimensional Gibbs functions for the species at their standard states of solution at the cu...
virtual doublereal hresid() const
Calculate the deviation terms for the total enthalpy of the mixture from the ideal gas mixture.
doublereal z() const
Calculate the value of z.
vector_fp m_h0_RT
Temporary storage for dimensionless reference state enthalpies.
virtual doublereal satPressure(doublereal TKelvin)
Calculate the saturation pressure at the current mixture content for the given temperature.
virtual void setState_TP(doublereal T, doublereal pres)
Set the temperature (K) and pressure (Pa)
virtual void _updateReferenceStateThermo() const
Updates the reference state thermodynamic functions at the current T of the solution.
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...
vector_fp m_s0_R
Temporary storage for dimensionless reference state entropies.
virtual void setState_TPX(doublereal t, doublereal p, const doublereal *x)
Set the temperature (K), pressure (Pa), and mole fractions.
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 doublereal sresid() const
Calculate the deviation terms for the total entropy of the mixture from the ideal gas mixture.
virtual void getCp_R(doublereal *cpr) const
Get the nondimensional Heat Capacities at constant pressure for the standard state of the species at ...
virtual void getEntropy_R(doublereal *sr) const
Get the array of nondimensional Enthalpy functions for the standard state species at the current T an...
virtual void setPressure(doublereal p)
Set the internally stored pressure (Pa) at constant temperature and composition.
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 psatEst(doublereal TKelvin) const
Estimate for the saturation pressure.
virtual doublereal liquidVolEst(doublereal TKelvin, doublereal &pres) const
Estimate for the molar volume of the liquid.
const vector_fp & gibbs_RT_ref() const
Returns the vector of nondimensional Gibbs free energies of the reference state at the current temper...
virtual int standardStateConvention() const
This method returns the convention used in specification of the standard state, of which there are cu...
virtual void getEntropy_R_ref(doublereal *er) const
Returns the vector of nondimensional entropies of the reference state at the current temperature of t...
virtual doublereal densSpinodalGas() const
Return the value of the density at the gas spinodal point (on the gas side) for the current temperatu...
virtual void getIntEnergy_RT(doublereal *urt) const
Returns the vector of nondimensional internal Energies of the standard state at the current temperatu...
virtual void setTemperature(const doublereal temp)
Set the temperature of the phase.
virtual void getCp_R_ref(doublereal *cprt) const
Returns the vector of nondimensional constant pressure heat capacities of the reference state at the ...
virtual doublereal pressureCalc(doublereal TKelvin, doublereal molarVol) const
Calculate the pressure given the temperature and the molar volume.
vector_fp moleFractions_
Storage for the current values of the mole fractions of the species.
doublereal m_Tlast_ref
The last temperature at which the reference state thermodynamic properties were calculated at.
doublereal calculatePsat(doublereal TKelvin, doublereal &molarVolGas, doublereal &molarVolLiquid)
Calculate the saturation pressure at the current mixture content for the given temperature.
virtual void getStandardChemPotentials(doublereal *mu) const
Get the array of chemical potentials at unit activity.
virtual void getStandardVolumes_ref(doublereal *vol) const
Get the molar volumes of the species reference states at the current T and P_ref of the solution.
int forcedState_
Force the system to be on a particular side of the spinodal curve.
virtual int forcedSolutionBranch() const
Report the solution branch which the solution is restricted to.
virtual void compositionChanged()
Apply changes to the state which are needed after the composition changes.
virtual void getChemPotentials_RT(doublereal *mu) const
Get the array of non-dimensional species chemical potentials These are partial molar Gibbs free energ...
virtual void setForcedSolutionBranch(int solnBranch)
Set the solution branch to force the ThermoPhase to exist on one branch or another.
int corr0(doublereal TKelvin, doublereal pres, doublereal &densLiq, doublereal &densGas, doublereal &liqGRT, doublereal &gasGRT)
Utility routine in the calculation of 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 void getGibbs_ref(doublereal *g) const
Returns the vector of the Gibbs function of the reference state at the current temperature of the sol...
virtual void invalidateCache()
Invalidate any cached values which are normally updated only when a change in state is detected.
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 getPureGibbs(doublereal *gpure) const
Get the pure Gibbs free energies of each species.
int phaseState(bool checkState=false) const
Returns the Phase State flag for the current state of the object.
virtual void getEnthalpy_RT_ref(doublereal *hrt) const
virtual void calcDensity()
Calculate the density of the mixture using the partial molar volumes and mole fractions as input.
virtual void update(doublereal T, doublereal *cp_R, doublereal *h_RT, doublereal *s_R) const
Compute the reference-state properties for all species.
An error indicating that an unimplemented function has been called.
Definition: ctexceptions.h:187
virtual void setMoleFractions(const double *const x)
Set the mole fractions to the specified values.
Definition: Phase.cpp:368
void setMoleFractionsByName(const compositionMap &xMap)
Set the species mole fractions by name.
Definition: Phase.cpp:409
size_t m_kk
Number of species in the phase.
Definition: Phase.h:942
virtual void setDensity(const double density_)
Set the internally stored density (kg/m^3) of the phase.
Definition: Phase.cpp:716
doublereal meanMolecularWeight() const
The mean molecular weight. Units: (kg/kmol)
Definition: Phase.h:748
void getMoleFractions(double *const x) const
Get the species mole fraction vector.
Definition: Phase.cpp:572
virtual double density() const
Density (kg/m^3).
Definition: Phase.h:685
virtual void compositionChanged()
Apply changes to the state which are needed after the composition changes.
Definition: Phase.cpp:1028
doublereal temperature() const
Temperature (K).
Definition: Phase.h:667
virtual void setTemperature(const doublereal temp)
Set the internally stored temperature of the phase (K).
Definition: Phase.h:724
void setMassFractionsByName(const compositionMap &yMap)
Set the species mass fractions by name.
Definition: Phase.cpp:445
virtual double pressure() const
Return the thermodynamic pressure (Pa).
Definition: Phase.h:679
virtual doublereal gibbs_mole() const
Molar Gibbs function. Units: J/kmol.
Definition: ThermoPhase.h:249
virtual bool addSpecies(shared_ptr< Species > spec)
virtual doublereal critPressure() const
Critical pressure (Pa).
Definition: ThermoPhase.h:1486
doublereal RT() const
Return the Gas Constant multiplied by the current temperature.
Definition: ThermoPhase.h:776
virtual doublereal critTemperature() const
Critical temperature (K).
Definition: ThermoPhase.h:1481
virtual void getChemPotentials(doublereal *mu) const
Get the species chemical potentials. Units: J/kmol.
Definition: ThermoPhase.h:489
virtual doublereal critDensity() const
Critical density (kg/m3).
Definition: ThermoPhase.h:1501
virtual doublereal refPressure() const
Returns the reference pressure in Pa.
Definition: ThermoPhase.h:145
MultiSpeciesThermo m_spthermo
Pointer to the calculation manager for species reference-state thermodynamic properties.
Definition: ThermoPhase.h:1870
virtual void invalidateCache()
Invalidate any cached values which are normally updated only when a change in state is detected.
Class XML_Node is a tree-based representation of the contents of an XML file.
Definition: xml.h:104
bool hasChild(const std::string &ch) const
Tests whether the current node has a child node with a particular name.
Definition: xml.cpp:528
CTML ("Cantera Markup Language") is the variant of XML that Cantera uses to store data.
void warn_user(const std::string &method, const std::string &msg, const Args &... args)
Definition: global.h:206
std::vector< double > vector_fp
Turn on the use of stl vectors for the basic array type within cantera Vector of doubles.
Definition: ct_defs.h:180
const double GasConstant
Universal Gas Constant [J/kmol/K].
Definition: ct_defs.h:109
Namespace for the Cantera kernel.
Definition: AnyMap.cpp:264
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:164
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:131
void scale(InputIter begin, InputIter end, OutputIter out, S scale_factor)
Multiply elements of an array by a scale factor.
Definition: utilities.h:135
const int cSS_CONVENTION_TEMPERATURE
Standard state uses the molar convention.
Definition: ThermoPhase.h:36
Contains declarations for string manipulation functions within Cantera.