Cantera  2.0
LatticePhase.cpp
Go to the documentation of this file.
1 /**
2  *
3  * @file LatticePhase.cpp
4  * Definitions for a simple thermodynamics model of a bulk phase
5  * derived from ThermoPhase,
6  * assuming a lattice of solid atoms
7  * (see \ref thermoprops and class \link Cantera::LatticePhase LatticePhase\endlink).
8  *
9  */
10 #include "cantera/base/config.h"
11 #include "cantera/base/ct_defs.h"
12 #include "cantera/thermo/mix_defs.h"
17 
18 #include <cmath>
19 #include <fstream>
20 
21 namespace Cantera
22 {
23 
24 // Base Empty constructor
26  m_mm(0),
27  m_tmin(0.0),
28  m_tmax(0.0),
29  m_Pref(OneAtm),
30  m_Pcurrent(OneAtm),
31  m_tlast(0.0),
32  m_speciesMolarVolume(0),
33  m_site_density(0.0)
34 {
35 }
36 
37 // Copy Constructor
38 /*
39  * @param right Object to be copied
40  */
42  m_mm(0),
43  m_tmin(0.0),
44  m_tmax(0.0),
45  m_Pref(OneAtm),
46  m_Pcurrent(OneAtm),
47  m_tlast(0.0),
48  m_speciesMolarVolume(0),
49  m_site_density(0.0)
50 {
51  *this = operator=(right);
52 }
53 
54 // Assignment operator
55 /*
56  * @param right Object to be copied
57  */
59 {
60  if (&right != this) {
62  m_mm = right.m_mm;
63  m_tmin = right.m_tmin;
64  m_tmax = right.m_tmax;
65  m_Pref = right.m_Pref;
66  m_Pcurrent = right.m_Pcurrent;
67  m_tlast = right.m_tlast;
68  m_h0_RT = right.m_h0_RT;
69  m_cp0_R = right.m_cp0_R;
70  m_g0_RT = right.m_g0_RT;
71  m_s0_R = right.m_s0_R;
72  m_vacancy = right.m_vacancy;
75  }
76  return *this;
77 }
78 
79 // Destructor
81 {
82 }
83 
84 
85 // Full constructor for a lattice phase
86 /*
87  * @param inputFile String name of the input file
88  * @param id string id of the phase name
89  */
90 LatticePhase::LatticePhase(std::string inputFile, std::string id)
91 {
92  constructPhaseFile(inputFile, id);
93 }
94 
95 // Full constructor for a water phase
96 /*
97  * @param phaseRef XML node referencing the lattice phase.
98  * @param id string id of the phase name
99  */
100 LatticePhase::LatticePhase(XML_Node& phaseRef, std::string id)
101 {
102  constructPhaseXML(phaseRef, id);
103 }
104 
105 
106 // Duplication function
107 /*
108  * This virtual function is used to create a duplicate of the
109  * current phase. It's used to duplicate the phase when given
110  * a ThermoPhase pointer to the phase.
111  *
112  * @return It returns a ThermoPhase pointer.
113  */
115 {
116  LatticePhase* igp = new LatticePhase(*this);
117  return (ThermoPhase*) igp;
118 }
119 
120 /*
121  * @param infile XML file containing the description of the
122  * phase
123  *
124  * @param id Optional parameter identifying the name of the
125  * phase. If none is given, the first XML
126  * phase element will be used.
127  */
128 void LatticePhase::constructPhaseXML(XML_Node& phaseNode, std::string idTarget)
129 {
130  std::string idattrib = phaseNode.id();
131  if (idTarget != idattrib) {
132  throw CanteraError("LatticePhase::constructPhaseXML","ids don't match");
133  }
134 
135  /*
136  * Call the Cantera importPhase() function. This will import
137  * all of the species into the phase. This will also handle
138  * all of the solvent and solute standard states.
139  */
140  bool m_ok = importPhase(phaseNode, this);
141  if (!m_ok) {
142  throw CanteraError("LatticePhase::constructPhaseXML","importPhase failed ");
143  }
144 }
145 
146 /*
147  * constructPhaseFile
148  *
149  *
150  * This routine is a precursor to constructPhaseXML(XML_Node*)
151  * routine, which does most of the work.
152  *
153  * @param inputFile XML file containing the description of the
154  * phase
155  *
156  * @param id Optional parameter identifying the name of the
157  * phase. If none is given, the first XML
158  * phase element will be used.
159  */
160 void LatticePhase::constructPhaseFile(std::string inputFile, std::string id)
161 {
162 
163  if (inputFile.size() == 0) {
164  throw CanteraError("LatticePhase::constructPhaseFile",
165  "input file is null");
166  }
167  std::string path = findInputFile(inputFile);
168  std::ifstream fin(path.c_str());
169  if (!fin) {
170  throw CanteraError("LatticePhase::constructPhaseFile","could not open "
171  +path+" for reading.");
172  }
173  /*
174  * The phase object automatically constructs an XML object.
175  * Use this object to store information.
176  */
177  XML_Node& phaseNode_XML = xml();
178  XML_Node* fxml = new XML_Node();
179  fxml->build(fin);
180  XML_Node* fxml_phase = findXMLPhase(fxml, id);
181  if (!fxml_phase) {
182  throw CanteraError("LatticePhase::constructPhaseFile",
183  "ERROR: Can not find phase named " +
184  id + " in file named " + inputFile);
185  }
186  fxml_phase->copy(&phaseNode_XML);
187  constructPhaseXML(*fxml_phase, id);
188  delete fxml;
189 }
190 
191 
192 doublereal LatticePhase::
194 {
195  doublereal p0 = m_spthermo->refPressure();
196  return GasConstant * temperature() *
197  mean_X(&enthalpy_RT_ref()[0])
198  + (pressure() - p0)/molarDensity();
199 }
200 
202 {
203  doublereal p0 = m_spthermo->refPressure();
204  return GasConstant * temperature() *
205  mean_X(&enthalpy_RT_ref()[0])
206  - p0/molarDensity();
207 }
208 
209 doublereal LatticePhase::entropy_mole() const
210 {
211  return GasConstant * (mean_X(&entropy_R_ref()[0]) -
212  sum_xlogx());
213 }
214 //====================================================================================================================
215 doublereal LatticePhase::gibbs_mole() const
216 {
217  return enthalpy_mole() - temperature() * entropy_mole();
218 }
219 //====================================================================================================================
220 doublereal LatticePhase::cp_mole() const
221 {
222  return GasConstant * mean_X(&cp_R_ref()[0]);
223 }
224 //====================================================================================================================
225 doublereal LatticePhase::cv_mole() const
226 {
227  return cp_mole();
228 }
229 //====================================================================================================================
231 {
233  doublereal mw = meanMolecularWeight();
234  doublereal dens = mw * m_site_density;
235  /*
236  * Calculate the molarVolume of the solution (m**3 kmol-1)
237  */
238  // const doublereal * const dtmp = moleFractdivMMW();
239  // doublereal invDens = dot(m_speciesMolarVolume.begin(), m_speciesMolarVolume.end(), dtmp);
240  /*
241  * Set the density in the parent State object directly,
242  * by calling the Phase::setDensity() function.
243  */
244  // doublereal dens = 1.0/invDens;
245  // Phase::setDensity(dens);
246  return dens;
247 }
248 //====================================================================================================================
249 void LatticePhase::setPressure(doublereal p)
250 {
251  m_Pcurrent = p;
252  calcDensity();
253 }
254 //====================================================================================================================
255 void LatticePhase::setMoleFractions(const doublereal* const x)
256 {
258  calcDensity();
259 }
260 //====================================================================================================================
261 void LatticePhase::setMoleFractions_NoNorm(const doublereal* const x)
262 {
264  calcDensity();
265 }
266 //====================================================================================================================
267 void LatticePhase::setMassFractions(const doublereal* const y)
268 {
270  calcDensity();
271 }
272 //====================================================================================================================
273 void LatticePhase::setMassFractions_NoNorm(const doublereal* const y)
274 {
276  calcDensity();
277 }
278 //====================================================================================================================
279 void LatticePhase::setConcentrations(const doublereal* const c)
280 {
282  calcDensity();
283 }
284 //====================================================================================================================
286 {
287  getMoleFractions(c);
288 }
289 //====================================================================================================================
290 void LatticePhase::getActivityCoefficients(doublereal* ac) const
291 {
292  for (size_t k = 0; k < m_kk; k++) {
293  ac[k] = 1.0;
294  }
295 }
296 //====================================================================================================================
297 doublereal LatticePhase::standardConcentration(size_t k) const
298 {
299  return 1.0;
300 }
301 //====================================================================================================================
302 doublereal LatticePhase::logStandardConc(size_t k) const
303 {
304  return 0.0;
305 }
306 //====================================================================================================================
307 void LatticePhase::getChemPotentials(doublereal* mu) const
308 {
309  doublereal delta_p = m_Pcurrent - m_Pref;
310  doublereal xx;
311  doublereal RT = temperature() * GasConstant;
312  const vector_fp& g_RT = gibbs_RT_ref();
313  for (size_t k = 0; k < m_kk; k++) {
315  mu[k] = RT * (g_RT[k] + log(xx))
316  + delta_p * m_speciesMolarVolume[k];
317  }
318 
319 }
320 //====================================================================================================================
321 void LatticePhase::getPartialMolarEnthalpies(doublereal* hbar) const
322 {
323  const vector_fp& _h = enthalpy_RT_ref();
324  doublereal rt = GasConstant * temperature();
325  scale(_h.begin(), _h.end(), hbar, rt);
326 }
327 //====================================================================================================================
328 void LatticePhase::getPartialMolarEntropies(doublereal* sbar) const
329 {
330  const vector_fp& _s = entropy_R_ref();
331  doublereal r = GasConstant;
332  doublereal xx;
333  for (size_t k = 0; k < m_kk; k++) {
335  sbar[k] = r * (_s[k] - log(xx));
336  }
337 }
338 //====================================================================================================================
339 void LatticePhase::getPartialMolarCp(doublereal* cpbar) const
340 {
341  getCp_R(cpbar);
342  for (size_t k = 0; k < m_kk; k++) {
343  cpbar[k] *= GasConstant;
344  }
345 }
346 //====================================================================================================================
347 void LatticePhase::getPartialMolarVolumes(doublereal* vbar) const
348 {
349  getStandardVolumes(vbar);
350 }
351 //====================================================================================================================
352 void LatticePhase::getStandardChemPotentials(doublereal* mu0) const
353 {
354  const vector_fp& gibbsrt = gibbs_RT_ref();
355  scale(gibbsrt.begin(), gibbsrt.end(), mu0, _RT());
356 }
357 //====================================================================================================================
358 void LatticePhase::getPureGibbs(doublereal* gpure) const
359 {
360  const vector_fp& gibbsrt = gibbs_RT_ref();
361  doublereal delta_p = (m_Pcurrent - m_Pref);
362  double RT = GasConstant * temperature();
363  for (size_t k = 0; k < m_kk; k++) {
364  gpure[k] = RT * gibbsrt[k] + delta_p * m_speciesMolarVolume[k];
365  }
366 }
367 //====================================================================================================================
368 void LatticePhase::getEnthalpy_RT(doublereal* hrt) const
369 {
370  const vector_fp& _h = enthalpy_RT_ref();
371  doublereal delta_prt = ((m_Pcurrent - m_Pref) / (GasConstant * temperature()));
372  for (size_t k = 0; k < m_kk; k++) {
373  hrt[k] = _h[k] + delta_prt * m_speciesMolarVolume[k];
374  }
375 }
376 //====================================================================================================================
377 void LatticePhase::getEntropy_R(doublereal* sr) const
378 {
379  const vector_fp& _s = entropy_R_ref();
380  std::copy(_s.begin(), _s.end(), sr);
381 }
382 //====================================================================================================================
383 void LatticePhase::getGibbs_RT(doublereal* grt) const
384 {
385  const vector_fp& gibbsrt = gibbs_RT_ref();
386  doublereal RT = _RT();
387  doublereal delta_prt = (m_Pcurrent - m_Pref)/ RT;
388  for (size_t k = 0; k < m_kk; k++) {
389  grt[k] = gibbsrt[k] + delta_prt * m_speciesMolarVolume[k];
390  }
391 }
392 //====================================================================================================================
393 void LatticePhase::getGibbs_ref(doublereal* g) const
394 {
395  getGibbs_RT_ref(g);
396  for (size_t k = 0; k < m_kk; k++) {
397  g[k] *= GasConstant * temperature();
398  }
399 }
400 //===================================================================================================================
401 
402 void LatticePhase::getCp_R(doublereal* cpr) const
403 {
404  const vector_fp& _cpr = cp_R_ref();
405  std::copy(_cpr.begin(), _cpr.end(), cpr);
406 }
407 //===================================================================================================================
408 void LatticePhase::getStandardVolumes(doublereal* vbar) const
409 {
410  copy(m_speciesMolarVolume.begin(), m_speciesMolarVolume.end(), vbar);
411 }
412 //=======================================================================================================
413 // Returns the vector of nondimensional Enthalpies of the reference state at the current temperature
414 // of the solution and the reference pressure for the phase.
415 /*
416  * @return Output vector of nondimensional reference state Enthalpies of the species.
417  * Length: m_kk
418  */
420 {
421  _updateThermo();
422  return m_h0_RT;
423 }
424 //=======================================================================================================
425 // Returns a reference to the dimensionless reference state Gibbs free energy vector.
426 /*
427  * This function is part of the layer that checks/recalculates the reference
428  * state thermo functions.
429  */
431 {
432  _updateThermo();
433  return m_g0_RT;
434 }
435 //====================================================================================================================
436 void LatticePhase::getGibbs_RT_ref(doublereal* grt) const
437 {
438  _updateThermo();
439  for (size_t k = 0; k < m_kk; k++) {
440  grt[k] = m_g0_RT[k];
441  }
442 }
443 //=======================================================================================================
444 // Returns a reference to the dimensionless reference state Entropy vector.
445 /*
446  * This function is part of the layer that checks/recalculates the reference
447  * state thermo functions.
448  */
450 {
451  _updateThermo();
452  return m_s0_R;
453 }
454 //=======================================================================================================
455 // Returns a reference to the dimensionless reference state Heat Capacity vector.
456 /*
457  * This function is part of the layer that checks/recalculates the reference
458  * state thermo functions.
459  */
461 {
462  _updateThermo();
463  return m_cp0_R;
464 }
465 //====================================================================================================================
466 // Initialize the ThermoPhase object after all species have been set up
467 /*
468  * @internal Initialize.
469  *
470  * This method performs any initialization required after all
471  * species have been added. For example, it is used to
472  * resize internal work arrays that must have an entry for
473  * each species.
474  * This method is called from ThermoPhase::initThermoXML(),
475  * which is called from importPhase(),
476  * just prior to returning from the function, importPhase().
477  *
478  * @see importCTML.cpp
479  */
481 {
482  m_kk = nSpecies();
483  m_mm = nElements();
484  doublereal tmin = m_spthermo->minTemp();
485  doublereal tmax = m_spthermo->maxTemp();
486  if (tmin > 0.0) {
487  m_tmin = tmin;
488  }
489  if (tmax > 0.0) {
490  m_tmax = tmax;
491  }
492  m_Pref = refPressure();
493 
494  size_t leng = m_kk;
495  m_h0_RT.resize(leng);
496  m_g0_RT.resize(leng);
497  m_cp0_R.resize(leng);
498  m_s0_R.resize(leng);
499  m_speciesMolarVolume.resize(leng, 0.0);
500 
502 }
503 //====================================================================================================================
504 void LatticePhase::initThermoXML(XML_Node& phaseNode, std::string id)
505 {
506  std::string subname = "LatticePhase::initThermoXML";
507  /*
508  * Check on the thermo field. Must have:
509  * <thermo model="Lattice" />
510  */
511  if (phaseNode.hasChild("thermo")) {
512  XML_Node& thNode = phaseNode.child("thermo");
513  std::string mStringa = thNode.attrib("model");
514  std::string mString = lowercase(mStringa);
515  if (mString != "lattice") {
516  throw CanteraError(subname.c_str(),
517  "Unknown thermo model: " + mStringa);
518  }
519  } else {
520  throw CanteraError(subname.c_str(),
521  "Unspecified thermo model");
522  }
523  /*
524  * Now go get the molar volumes. use the default if not found
525  */
526  XML_Node& speciesList = phaseNode.child("speciesArray");
527  XML_Node* speciesDB = get_XML_NameID("speciesData", speciesList["datasrc"], &phaseNode.root());
528  const std::vector<std::string> &sss = speciesNames();
529 
530  for (size_t k = 0; k < m_kk; k++) {
532  XML_Node* s = speciesDB->findByAttr("name", sss[k]);
533  if (!s) {
534  throw CanteraError(" LatticePhase::initThermoXML", "database problems");
535  }
536  XML_Node* ss = s->findByName("standardState");
537  if (ss) {
538  if (ss->findByName("molarVolume")) {
539  m_speciesMolarVolume[k] = ctml::getFloat(*ss, "molarVolume", "toSI");
540  }
541  }
542  }
543 
544  /*
545  * Call the base initThermo, which handles setting the initial
546  * state.
547  */
548  ThermoPhase::initThermoXML(phaseNode, id);
549 }
550 //=====================================================================================================
551 // Update the species reference state thermodynamic functions
552 /*
553  * The polynomials for the standard state functions are only
554  * reevaluated if the temperature has changed.
555  */
557 {
558  doublereal tnow = temperature();
559  if (m_tlast != tnow) {
560  m_spthermo->update(tnow, &m_cp0_R[0], &m_h0_RT[0], &m_s0_R[0]);
561  m_tlast = tnow;
562  for (size_t k = 0; k < m_kk; k++) {
563  m_g0_RT[k] = m_h0_RT[k] - m_s0_R[k];
564  }
565  m_tlast = tnow;
566  }
567 }
568 //=====================================================================================================
569 void LatticePhase::setParameters(int n, doublereal* const c)
570 {
571  m_site_density = c[0];
573 }
574 //=====================================================================================================
575 void LatticePhase::getParameters(int& n, doublereal* const c) const
576 {
577  double d = molarDensity();
578  c[0] = d;
579  n = 1;
580 }
581 //=====================================================================================================
583 {
584  eosdata._require("model", "Lattice");
585  m_site_density = ctml::getFloat(eosdata, "site_density", "toSI");
586  m_vacancy = ctml::getChildValue(eosdata, "vacancy_species");
587 }
588 //=====================================================================================================
589 }
590 //=======================================================================================================