Cantera  2.1.2
Elements.cpp
Go to the documentation of this file.
1 /**
2  * @file Elements.cpp
3  * This file contains a database of atomic weights.
4  */
5 
6 // Copyright 2003 California Institute of Technology
7 
9 #include "cantera/base/xml.h"
10 #include "cantera/base/ctml.h"
13 
14 using namespace ctml;
15 using namespace std;
16 
17 namespace Cantera
18 {
19 
20 
21 /*! Database for atomic molecular weights
22  * Values are taken from the 1989 Standard Atomic Weights, CRC
23  *
24  * awTable[] is a static function with scope limited to this file.
25  * It can only be referenced via the LookupWtElements() function.
26  *
27  * units = kg / kg-mol (or equivalently gm / gm-mol)
28  *
29  * This structure was picked because it's simple, compact, and extensible.
30  */
31 struct awData {
32  char name[4]; //!< Null Terminated name, First letter capitalized
33  double atomicWeight; //!< atomic weight in kg / kg-mol
34 };
35 
36 /*!
37  * @var static struct awData aWTable[]
38  * \brief aWTable is a vector containing the atomic weights database.
39  *
40  * The size of the table is given by the initial instantiation.
41  */
42 static struct awData aWTable[] = {
43  {"H", 1.00794},
44  {"D", 2.0 },
45  {"Tr", 3.0 },
46  {"He", 4.002602},
47  {"Li", 6.941 },
48  {"Be", 9.012182},
49  {"B", 10.811 },
50  {"C", 12.011 },
51  {"N", 14.00674},
52  {"O", 15.9994 },
53  {"F", 18.9984032},
54  {"Ne", 20.1797 },
55  {"Na", 22.98977},
56  {"Mg", 24.3050 },
57  {"Al", 26.98154},
58  {"Si", 28.0855 },
59  {"P", 30.97376},
60  {"S", 32.066 },
61  {"Cl", 35.4527 },
62  {"Ar", 39.948 },
63  {"K", 39.0983 },
64  {"Ca", 40.078 },
65  {"Sc", 44.95591},
66  {"Ti", 47.88 },
67  {"V", 50.9415 },
68  {"Cr", 51.9961 },
69  {"Mn", 54.9381 },
70  {"Fe", 55.847 },
71  {"Co", 58.9332 },
72  {"Ni", 58.69 },
73  {"Cu", 63.546 },
74  {"Zn", 65.39 },
75  {"Ga", 69.723 },
76  {"Ge", 72.61 },
77  {"As", 74.92159},
78  {"Se", 78.96 },
79  {"Br", 79.904 },
80  {"Kr", 83.80 },
81  {"Rb", 85.4678 },
82  {"Sr", 87.62 },
83  {"Y", 88.90585},
84  {"Zr", 91.224 },
85  {"Nb", 92.90638},
86  {"Mo", 95.94 },
87  {"Tc", 97.9072 },
88  {"Ru", 101.07 },
89  {"Rh", 102.9055 },
90  {"Pd", 106.42 },
91  {"Ag", 107.8682 },
92  {"Cd", 112.411 },
93  {"In", 114.82 },
94  {"Sn", 118.710 },
95  {"Sb", 121.75 },
96  {"Te", 127.6 },
97  {"I", 126.90447},
98  {"Xe", 131.29 },
99  {"Cs", 132.90543},
100  {"Ba", 137.327 },
101  {"La", 138.9055 },
102  {"Ce", 140.115 },
103  {"Pr", 140.90765},
104  {"Nd", 144.24 },
105  {"Pm", 144.9127 },
106  {"Sm", 150.36 },
107  {"Eu", 151.965 },
108  {"Gd", 157.25 },
109  {"Tb", 158.92534},
110  {"Dy", 162.50 },
111  {"Ho", 164.93032},
112  {"Er", 167.26 },
113  {"Tm", 168.93421},
114  {"Yb", 173.04 },
115  {"Lu", 174.967 },
116  {"Hf", 178.49 },
117  {"Ta", 180.9479 },
118  {"W", 183.85 },
119  {"Re", 186.207 },
120  {"Os", 190.2 },
121  {"Ir", 192.22 },
122  {"Pt", 195.08 },
123  {"Au", 196.96654},
124  {"Hg", 200.59 },
125  {"Ti", 204.3833 },
126  {"Pb", 207.2 },
127  {"Bi", 208.98037},
128  {"Po", 208.9824 },
129  {"At", 209.9871 },
130  {"Rn", 222.0176 },
131  {"Fr", 223.0197 },
132  {"Ra", 226.0254 },
133  {"Ac", 227.0279 },
134  {"Th", 232.0381 },
135  {"Pa", 231.03588},
136  {"U", 238.0508 },
137  {"Np", 237.0482 },
138  {"Pu", 244.0482 }
139 };
140 
141 
142 // Static function to look up an atomic weight
143 /*
144  * This static function looks up the argument string in the
145  * database above and returns the associated molecular weight.
146  * The data are from the periodic table.
147  *
148  * Note: The idea behind this function is to provide a unified
149  * source for the element atomic weights. This helps to
150  * ensure that mass is conserved.
151  *
152  * @param s String, Only the first 3 characters are significant
153  *
154  * @return
155  * Return value contains the atomic weight of the element
156  * If a match for the string is not found, a value of -1.0 is
157  * returned.
158  *
159  * @exception CanteraError
160  * If a match is not found, a CanteraError is thrown as well
161  */
162 doublereal Elements::LookupWtElements(const std::string& ename)
163 {
164  int num = sizeof(aWTable) / sizeof(struct awData);
165  string s3 = ename.substr(0,3);
166  for (int i = 0; i < num; i++) {
167  if (s3 == aWTable[i].name) {
168  return aWTable[i].atomicWeight;
169  }
170  }
171  throw CanteraError("LookupWtElements", "element not found");
172  return -1.0;
173 }
174 
175 doublereal LookupWtElements(const std::string& ename)
176 {
177  int num = sizeof(aWTable) / sizeof(struct awData);
178  string s3 = ename.substr(0,3);
179  for (int i = 0; i < num; i++) {
180  if (s3 == aWTable[i].name) {
181  return aWTable[i].atomicWeight;
182  }
183  }
184  throw CanteraError("LookupWtElements", "element not found");
185  return -1.0;
186 }
187 
188 
189 
190 
191 
192 //! Exception class to indicate a fixed set of elements.
193 /*!
194  * This class is used to warn the user when the number of elements
195  * are changed after at least one species is defined.
196  */
198 {
199 public:
200  //! Constructor for class
201  /*!
202  * @param func Function where the error occurred.
203  */
204  ElementsFrozen(string func)
205  : CanteraError(func,
206  "elements cannot be added after species.") {}
207 };
208 
209 /*
210  * Elements Class Constructor
211  * We initialize all internal variables to zero here.
212  */
213 Elements::Elements() :
214  m_mm(0),
215  m_elementsFrozen(false),
216  m_elem_type(0),
217  numSubscribers(0)
218 {
219  warn_deprecated("class Elements");
220 }
221 
222 /*
223  * Elements Class Destructor
224  * If the number of subscribers is not zero, through an error.
225  * A logic problem has occurred.
226  *
227  * @exception CanteraError
228  */
230 {
231  if (numSubscribers != 0) {
232  throw CanteraError("~Elements", "numSubscribers not zero");
233  }
234 }
235 
237  m_mm(0),
238  m_elementsFrozen(false),
239  numSubscribers(0)
240 {
241  *this = operator=(right);
242 }
243 
245 {
246  if (&right == this) {
247  return *this;
248  }
249 
250  m_mm = right.m_mm;
255  m_entropy298 = right.m_entropy298;
256  m_elem_type = right.m_elem_type;
257  numSubscribers = 0;
258 
259  return *this;
260 }
261 
262 
263 
264 /*
265  * freezeElements():
266  *
267  * Set the freeze flag. This is a prerequesite to other
268  * activivities, i.e., this is done before species are defined.
269  */
271 {
272  m_elementsFrozen = true;
273 }
274 
275 /*
276  * elementIndex():
277  *
278  * Index of element named \c name. The index is an integer
279  * assigned to each element in the order it was added,
280  * beginning with 0 for the first element. If \c name is not
281  * the name of an element in the set, then the value -1 is
282  * returned.
283  *
284  */
285 int Elements::elementIndex(const std::string& name) const
286 {
287  for (int i = 0; i < m_mm; i++) {
288  if (m_elementNames[i] == name) {
289  return i;
290  }
291  }
292  return -1;
293 }
294 
295 /*
296  *
297  * Name of the element with index \c m. @param m Element
298  * index. If m < 0 or m >= nElements() an exception is thrown.
299  */
300 string Elements::elementName(int m) const
301 {
302  if (m < 0 || m >= nElements()) {
303  throw CanteraError("Elements::elementName()", "out of bounds: " + int2str(m) + " " + int2str(nElements()));
304  }
305  return m_elementNames[m];
306 }
307 
308 
309 doublereal Elements::entropyElement298(int m) const
310 {
312  "Elements::entropy298",
313  "Entropy at 298 K of element is unknown");
314  AssertTrace(m >= 0 && m < m_mm);
315  return m_entropy298[m];
316 }
317 //====================================================================================================================
318 //! Return the element constraint type
319 /*!
320  * Possible types include:
321  *
322  * CT_ELEM_TYPE_TURNEDOFF -1
323  * CT_ELEM_TYPE_ABSPOS 0
324  * CT_ELEM_TYPE_ELECTRONCHARGE 1
325  * CT_ELEM_TYPE_CHARGENEUTRALITY 2
326  * CT_ELEM_TYPE_LATTICERATIO 3
327  * CT_ELEM_TYPE_KINETICFROZEN 4
328  * CT_ELEM_TYPE_SURFACECONSTRAINT 5
329  * CT_ELEM_TYPE_OTHERCONSTRAINT 6
330  *
331  * The default is CT_ELEM_TYPE_ABSPOS
332  */
333 int Elements::elementType(int m) const
334 {
335  return m_elem_type[m];
336 }
337 //====================================================================================================================
338 // Change the element type of the mth constraint
339 /*
340  * Reassigns an element type
341  *
342  * @param m Element index
343  * @param elem_type New elem type to be assigned
344  *
345  * @return Returns the old element type
346  */
347 int Elements::changeElementType(int m, int elem_type)
348 {
349  int old = m_elem_type[m];
350  m_elem_type[m] = elem_type;
351  return old;
352 }
353 //====================================================================================================================
354 /*
355  *
356  * Add an element to the current set of elements in the current object.
357  * @param symbol symbol string
358  * @param weight atomic weight in kg/kmol.
359  *
360  * The default weight is a special value, which will cause the
361  * routine to look up the actual weight via a string lookup.
362  *
363  * There are two interfaces to this routine. The XML interface
364  * looks up the required parameters for the regular interface
365  * and then calls the base routine.
366  */
367 void Elements::
368 addElement(const std::string& symbol, doublereal weight)
369 {
370  if (weight == -12345.0) {
371  weight = LookupWtElements(symbol);
372  if (weight < 0.0) {
373  throw ElementsFrozen("addElement");
374  }
375  }
376  if (m_elementsFrozen) {
377  throw ElementsFrozen("addElement");
378  return;
379  }
380  m_atomicWeights.push_back(weight);
381  m_elementNames.push_back(symbol);
382  if (symbol == "E") {
384  } else {
385  m_elem_type.push_back(CT_ELEM_TYPE_ABSPOS);
386  }
387 
388  m_mm++;
389 }
390 //===========================================================================================================
391 void Elements::
393 {
394  doublereal weight = fpValue(e["atomicWt"]);
395  string symbol = e["name"];
396  addElement(symbol, weight);
397 }
398 //===========================================================================================================
399 /*
400  * addUniqueElement():
401  *
402  * Add a unique element to the set. This routine will not allow
403  * duplicate elements to be input.
404  *
405  * @param symbol symbol string
406  * @param weight atomic weight in kg/kmol.
407  *
408  *
409  * The default weight is a special value, which will cause the
410  * routine to look up the actual weight via a string lookup.
411  */
412 void Elements::
413 addUniqueElement(const std::string& symbol,
414  doublereal weight, int atomicNumber_, doublereal entropy298,
415  int elem_type)
416 {
417  if (weight == -12345.0) {
418  weight = LookupWtElements(symbol);
419  if (weight < 0.0) {
420  throw ElementsFrozen("addElement");
421  }
422  }
423  /*
424  * First decide if this element has been previously added
425  * by conducting a string search. If it unique, add it to
426  * the list.
427  */
428  int ifound = 0;
429  int i = 0;
430  for (vector<string>::const_iterator it = m_elementNames.begin();
431  it < m_elementNames.end(); ++it, ++i) {
432  if (*it == symbol) {
433  ifound = 1;
434  break;
435  }
436  }
437  if (!ifound) {
438  if (m_elementsFrozen) {
439  throw ElementsFrozen("addElement");
440  return;
441  }
442  m_atomicWeights.push_back(weight);
443  m_elementNames.push_back(symbol);
444  m_atomicNumbers.push_back(atomicNumber_);
445  m_entropy298.push_back(entropy298);
446  if (symbol == "E") {
448  } else {
449  m_elem_type.push_back(elem_type);
450  }
451  m_mm++;
452  } else {
453  if (m_atomicWeights[i] != weight) {
454  throw CanteraError("AddUniqueElement",
455  "Duplicate Elements (" + symbol + ") have different weights");
456  }
457  }
458 }
459 
460 /*
461  * @todo call addUniqueElement(symbol, weight) instead of
462  * addElement.
463  */
464 void Elements::
466 {
467  doublereal weight = 0.0;
468  if (e.hasAttrib("atomicWt")) {
469  weight = fpValue(stripws(e["atomicWt"]));
470  }
471  int anum = 0;
472  if (e.hasAttrib("atomicNumber")) {
473  anum = atoi(stripws(e["atomicNumber"]).c_str());
474  }
475  string symbol = e["name"];
476  doublereal entropy298 = ENTROPY298_UNKNOWN;
477  if (e.hasChild("entropy298")) {
478  XML_Node& e298Node = e.child("entropy298");
479  if (e298Node.hasAttrib("value")) {
480  entropy298 = fpValueCheck(stripws(e298Node["value"]));
481  }
482  }
483  if (weight != 0.0) {
484  addUniqueElement(symbol, weight, anum, entropy298);
485  } else {
486  addUniqueElement(symbol);
487  }
488 }
489 
490 // True if freezeElements has been called.
492 {
493  return m_elementsFrozen;
494 }
495 
496 /*
497  * clear()
498  *
499  * Remove all elements from the structure.
500  */
502 {
503  m_mm = 0;
504  m_atomicWeights.resize(0);
505  m_elementNames.resize(0);
506  m_entropy298.resize(0);
507  m_elem_type.resize(0);
508  m_elementsFrozen = false;
509 }
510 
511 /*
512  * ready():
513  *
514  * True if the elements have been frozen
515  */
516 bool Elements::ready() const
517 {
518  return m_elementsFrozen;
519 }
520 
521 
523 {
524 
525  // get the declared element names
526  if (! phase.hasChild("elementArray")) {
527  throw CanteraError("Elements::addElementsFromXML",
528  "phase xml node doesn't have \"elementArray\" XML Node");
529  }
530  XML_Node& elements = phase.child("elementArray");
531  vector<string> enames;
532  getStringArray(elements, enames);
533 
534  // // element database defaults to elements.xml
535  string element_database = "elements.xml";
536  if (elements.hasAttrib("datasrc")) {
537  element_database = elements["datasrc"];
538  }
539 
540  XML_Node* doc = get_XML_File(element_database);
541  XML_Node* dbe = &doc->child("ctml/elementData");
542 
543  XML_Node& root = phase.root();
544  XML_Node* local_db = 0;
545  if (root.hasChild("ctml")) {
546  if (root.child("ctml").hasChild("elementData")) {
547  local_db = &root.child("ctml/elementData");
548  }
549  }
550 
551  int nel = static_cast<int>(enames.size());
552  int i;
553  string enm;
554  XML_Node* e = 0;
555  for (i = 0; i < nel; i++) {
556  e = 0;
557  if (local_db) {
558  //writelog("looking in local database.");
559  e = local_db->findByAttr("name",enames[i]);
560  //if (!e) writelog(enames[i]+" not found.");
561  }
562  if (!e) {
563  e = dbe->findByAttr("name",enames[i]);
564  }
565  if (e) {
566  addUniqueElement(*e);
567  } else {
568  throw CanteraError("addElementsFromXML","no data for element "
569  +enames[i]);
570  }
571  }
572 
573 }
574 
575 /*
576  * subscribe(), unsubscribe(), and reportSubscriptions():
577  *
578  * Handles setting and reporting the number of subscriptions to this
579  * object.
580  */
582 {
583  ++numSubscribers;
584 }
586 {
587  --numSubscribers;
588  return numSubscribers;
589 }
591 {
592  return numSubscribers;
593 }
594 
595 /********************* GLOBAL STATIC SECTION **************************/
596 /*
597  * We keep track of a vector of pointers to element objects.
598  * Initially there are no Elements objects. Whenever one is created,
599  * the pointer to that object is added onto this list.
600  */
601 vector<Elements*> Elements::Global_Elements_List;
602 /***********************************************************************/
603 }
std::string elementName(int m) const
Name of the element with index m.
Definition: Elements.cpp:300
doublereal fpValue(const std::string &val)
Translate a string into one doublereal value.
XML_Node * findByAttr(const std::string &attr, const std::string &val, int depth=100000) const
This routine carries out a recursive search for an XML node based on an attribute of each XML node...
Definition: xml.cpp:716
std::string int2str(const int n, const std::string &fmt)
Convert an int to a string using a format converter.
Definition: stringUtils.cpp:40
doublereal LookupWtElements(const std::string &ename)
Function to look up an atomic weight This function looks up the argument string in the database above...
Definition: Elements.cpp:175
void addUniqueElement(const std::string &symbol, doublereal weight=-12345.0, int atomicNumber=0, doublereal entropy298=ENTROPY298_UNKNOWN, int elem_type=CT_ELEM_TYPE_ABSPOS)
Add an element only if the element hasn't been added before.
Definition: Elements.cpp:413
XML_Node * get_XML_File(const std::string &file, int debug)
Return a pointer to the XML tree for a Cantera input file.
Definition: global.cpp:144
CTML ("Cantera Markup Language") is the variant of XML that Cantera uses to store data...
void clear()
Remove all elements.
Definition: Elements.cpp:501
void addElement(const std::string &symbol, doublereal weight=-12345.0)
Add an element to the current set of elements in the current object.
Definition: Elements.cpp:368
Elements()
Default constructor for the elements class.
Definition: Elements.cpp:213
Class XML_Node is a tree-based representation of the contents of an XML file.
Definition: xml.h:100
Contains the LookupWtElements function and the definitions of element constraint types.
void warn_deprecated(const std::string &method, const std::string &extra)
Print a warning indicating that method is deprecated.
Definition: global.cpp:76
bool elementsFrozen() const
True if freezeElements has been called.
Definition: Elements.cpp:491
void subscribe()
subscribe to this object
Definition: Elements.cpp:581
#define CT_ELEM_TYPE_ABSPOS
Normal element constraint consisting of positive coefficients for the formula matrix.
Definition: Elements.h:35
vector_int m_elem_type
Vector of element types.
Definition: Elements.h:395
#define CT_ELEM_TYPE_ELECTRONCHARGE
This refers to conservation of electrons.
Definition: Elements.h:41
void freezeElements()
Prohibit addition of more elements, and prepare to add species.
Definition: Elements.cpp:270
int reportSubscriptions() const
report the number of subscriptions
Definition: Elements.cpp:590
#define AssertThrowMsg(expr, procedure, message)
Assertion must be true or an error is thrown.
Definition: ctexceptions.h:247
bool ready() const
True if both elements and species have been frozen.
Definition: Elements.cpp:516
XML_Node & child(const size_t n) const
Return a changeable reference to the n'th child of the current node.
Definition: xml.cpp:584
bool m_elementsFrozen
boolean indicating completion of object
Definition: Elements.h:367
std::string stripws(const std::string &s)
Strip the leading and trailing white space from a string.
static struct awData aWTable[]
aWTable is a vector containing the atomic weights database.
Definition: Elements.cpp:42
vector_fp m_atomicWeights
Vector of element atomic weights:
Definition: Elements.h:374
ElementsFrozen(string func)
Constructor for class.
Definition: Elements.cpp:204
Object containing the elements that make up species in a phase.
Definition: Elements.h:116
Classes providing support for XML data files.
Base class for exceptions thrown by Cantera classes.
Definition: ctexceptions.h:68
int nElements() const
Inline function that returns the number of elements in the object.
Definition: Elements.h:236
Exception class to indicate a fixed set of elements.
Definition: Elements.cpp:197
bool hasChild(const std::string &ch) const
Tests whether the current node has a child node with a particular name.
Definition: xml.cpp:574
static std::vector< Elements * > Global_Elements_List
Vector of pointers to Elements Objects.
Definition: Elements.h:412
#define ENTROPY298_UNKNOWN
Number indicating we don't know the entropy of the element in its most stable state at 298...
Definition: Elements.h:84
#define AssertTrace(expr)
Assertion must be true or an error is thrown.
Definition: ctexceptions.h:216
doublereal entropyElement298(int m) const
Entropy at 298.15 K and 1 bar of stable state of the element.
Definition: Elements.cpp:309
Elements & operator=(const Elements &right)
Assignment operator.
Definition: Elements.cpp:244
void getStringArray(const Cantera::XML_Node &node, std::vector< std::string > &v)
This function interprets the value portion of an XML element as a string.
Definition: ctml.cpp:639
double atomicWeight
atomic weight in kg / kg-mol
Definition: Elements.cpp:33
std::vector< std::string > m_elementNames
Vector of strings containing the names of the elements.
Definition: Elements.h:386
static double LookupWtElements(const std::string &ename)
Static function to look up an atomic weight.
Definition: Elements.cpp:162
void addElementsFromXML(const XML_Node &phase)
Add multiple elements from a XML_Node phase description.
Definition: Elements.cpp:522
Contains declarations for string manipulation functions within Cantera.
vector_int m_atomicNumbers
Vector of element atomic numbers:
Definition: Elements.h:380
int m_mm
Number of elements.
Definition: Elements.h:359
int changeElementType(int m, int elem_type)
Change the element type of the mth constraint.
Definition: Elements.cpp:347
vector_fp m_entropy298
Entropy at 298.15 K and 1 bar of stable state.
Definition: Elements.h:392
XML_Node & root() const
Return the root of the current XML_Node tree.
Definition: xml.cpp:1091
int elementIndex(const std::string &name) const
Function that returns the index of an element.
Definition: Elements.cpp:285
doublereal fpValueCheck(const std::string &val)
Translate a string into one doublereal value, with error checking.
~Elements()
Default destructor for the elements class.
Definition: Elements.cpp:229
Definitions for the classes that are thrown when Cantera experiences an error condition (also contain...
int numSubscribers
Number of Constituents Objects that use this object.
Definition: Elements.h:404
bool hasAttrib(const std::string &a) const
Tests whether the current node has an attribute with a particular name.
Definition: xml.cpp:579
int unsubscribe()
unsubscribe to this object
Definition: Elements.cpp:585
int elementType(int m) const
Return the element constraint type.
Definition: Elements.cpp:333