Skip to content

Commit

Permalink
[Elements] Add helper methods for elements
Browse files Browse the repository at this point in the history
The methods added here get the element symbols and names as vectors of
strings and a map of the element symbols and names to the atomic
weights. This is simplified by converting the weight tables to
std::vectors instead of C-style vectors.
  • Loading branch information
bryanwweber authored and speth committed Jun 24, 2022
1 parent 186fddc commit 840aea9
Show file tree
Hide file tree
Showing 4 changed files with 146 additions and 37 deletions.
34 changes: 34 additions & 0 deletions include/cantera/thermo/Elements.h
Expand Up @@ -84,6 +84,40 @@ namespace Cantera
//! stable state at 298.15 K and 1 bar.
#define ENTROPY298_UNKNOWN -123456789.

//! Get a vector of the atomic symbols of the elements defined in Cantera.
const std::vector<std::string>& elementSymbols();

//! Get a vector of the names of the elements defined in Cantera.
const std::vector<std::string>& elementNames();

//! Get a map with the element symbols as keys and weights as values.
/*!
* This is a constant in the application so it is only generated once
* when it is first needed.
*/
const std::map<std::string, double>& elementSymbolToWeight();

//! Get a map with the element names as keys and weights as values.
/*!
* This is a constant in the application so it is only generated once
* when it is first needed.
*/
const std::map<std::string, double>& elementNameToWeight();

//! Get a map with the isotope symbols as keys and weights as values.
/*!
* This is a constant in the application so it is only generated once
* when it is first needed.
*/
const std::map<std::string, double>& isotopeSymbolToWeight();

//! Get a map with the isotope names as keys and weights as values.
/*!
* This is a constant in the application so it is only generated once
* when it is first needed.
*/
const std::map<std::string, double>& isotopeNameToWeight();

//! Get the atomic weight of an element.
/*!
* Get the atomic weight of an element defined in Cantera by its symbol
Expand Down
2 changes: 2 additions & 0 deletions interfaces/cython/cantera/_cantera.pxd
Expand Up @@ -1563,6 +1563,8 @@ cdef wrapSpeciesThermo(shared_ptr[CxxSpeciesThermo] spthermo)
cdef int assign_delegates(object, CxxDelegator*) except -1

cdef extern from "cantera/thermo/Elements.h" namespace "Cantera":
vector[string] elementSymbols()
vector[string] elementNames()
double getElementWeight(string ename) except +translate_exception
double getElementWeight(int atomicNumber) except +translate_exception
int numElementsDefined()
Expand Down
15 changes: 11 additions & 4 deletions interfaces/cython/cantera/thermo.pyx
Expand Up @@ -2046,6 +2046,15 @@ cdef class PureFluid(ThermoPhase):
return self.s, self.v, self.Q


def _element_symbols():
syms = elementSymbols()
return tuple(pystr(s) for s in syms)


def _element_names():
names = elementNames()
return tuple(pystr(n) for n in names)

class Element:
"""
An element or a named isotope defined in Cantera.
Expand Down Expand Up @@ -2092,13 +2101,11 @@ class Element:

#: A list of the symbols of all the elements (not isotopes) defined
#: in Cantera
element_symbols = [pystr(getElementSymbol(<int>(m+1)))
for m in range(num_elements_defined)]
element_symbols = _element_symbols()

#: A list of the names of all the elements (not isotopes) defined
#: in Cantera
element_names = [pystr(getElementName(<int>m+1))
for m in range(num_elements_defined)]
element_names = _element_names()

def __init__(self, arg):
if isinstance(arg, (str, bytes)):
Expand Down
132 changes: 99 additions & 33 deletions src/thermo/Elements.cpp
Expand Up @@ -58,15 +58,15 @@ struct isotopeWeightData {
};

/*!
* @var static struct atomicWeightData atomicWeightTable[]
* @var static vector<atomicWeightData> atomicWeightTable
* \brief atomicWeightTable is a vector containing the atomic weights database.
*
* atomicWeightTable[] is a static variable with scope limited to this file.
* atomicWeightTable is a static variable with scope limited to this file.
* It can only be referenced via the functions in this file.
*
* The size of the table is given by the initial instantiation.
*/
static struct atomicWeightData atomicWeightTable[] = {
static vector<atomicWeightData> atomicWeightTable {
{"H", "hydrogen", 1.008},
{"He", "helium", 4.002602},
{"Li", "lithium", 6.94},
Expand Down Expand Up @@ -188,36 +188,106 @@ static struct atomicWeightData atomicWeightTable[] = {
};

/*!
* @var static struct isotopeWeightData isotopeWeightTable[]
* @var static vector<isotopeWeightData> isotopeWeightTable
* \brief isotopeWeightTable is a vector containing the atomic weights database.
*
* isotopeWeightTable[] is a static function with scope limited to this file.
* isotopeWeightTable is a static variable with scope limited to this file.
* It can only be referenced via the functions in this file.
*
* The size of the table is given by the initial instantiation.
*/
static struct isotopeWeightData isotopeWeightTable[] = {
static vector<isotopeWeightData> isotopeWeightTable {
// M. Wang et al. The AME2016 atomic mass evaluation. Chinese Physics C.
// doi:10.1088/1674-1137/41/3/030003.
{"D", "deuterium", 2.0141017781, 1},
{"Tr", "tritium", 3.0160492820, 1},
{"E", "electron", ElectronMass * Avogadro, 0},
};

// This is implemented as a separate function from elementSymbols() because this pattern
// allows elementSymbols() to return a const reference to the data.
vector<string> elementVectorsFromSymbols() {
vector<string> values;
for (const auto& atom: atomicWeightTable) {
values.push_back(atom.symbol);
}
return values;
}

const vector<string>& elementSymbols() {
const static vector<string> values = elementVectorsFromSymbols();
return values;
}

// This is implemented as a separate function from elementNames() because this pattern
// allows elementNames() to return a const reference to the data.
vector<string> elementVectorsFromNames() {
vector<string> values;
for (const auto& atom: atomicWeightTable) {
values.push_back(atom.fullName);
}
return values;
}

const vector<string>& elementNames() {
const static vector<string> values = elementVectorsFromNames();
return values;
}

template<typename T>
map<string, double> mapAtomicWeights(vector<T> data, bool symbol, bool name) {
map<string, double> symMap;

for (auto const& atom : data) {
if (symbol) {
symMap.emplace(atom.symbol, atom.atomicWeight);
} else if (name) {
symMap.emplace(atom.fullName, atom.atomicWeight);
}
}
return symMap;
}

const map<string, double>& elementSymbolToWeight() {
const static map<string, double> symMap = mapAtomicWeights(atomicWeightTable,
true, false);
return symMap;
}

const map<string, double>& elementNameToWeight() {
const static map<string, double> symMap = mapAtomicWeights(atomicWeightTable,
false, true);
return symMap;
}

const map<string, double>& isotopeSymbolToWeight() {
const static map<string, double> symMap = mapAtomicWeights(isotopeWeightTable,
true, false);
return symMap;
}

const map<string, double>& isotopeNameToWeight() {
const static map<string, double> symMap = mapAtomicWeights(isotopeWeightTable,
false, true);
return symMap;
}

double getElementWeight(const std::string& ename)
{
int numElements = numElementsDefined();
int numIsotopes = numIsotopesDefined();
const auto& elementSymbolMap = elementSymbolToWeight();
const auto& elementNameMap = elementNameToWeight();
const auto& isotopeSymbolMap = isotopeSymbolToWeight();
const auto& isotopeNameMap = isotopeNameToWeight();
double elementWeight = 0.0;
string symbol = trimCopy(ename);
string name = toLowerCopy(symbol);
for (int i = 0; i < numElements; i++) {
if (symbol == atomicWeightTable[i].symbol) {
elementWeight = atomicWeightTable[i].atomicWeight;
break;
} else if (name == atomicWeightTable[i].fullName) {
elementWeight = atomicWeightTable[i].atomicWeight;
break;
auto search = elementSymbolMap.find(symbol);
if (search != elementSymbolMap.end()) {
elementWeight = search->second;
} else {
search = elementNameMap.find(name);
if (search != elementNameMap.end()) {
elementWeight = search->second;
}
}
if (elementWeight > 0.0) {
Expand Down Expand Up @@ -257,17 +327,15 @@ double getElementWeight(int atomicNumber)

string getElementSymbol(const std::string& ename)
{
int numElements = numElementsDefined();
int numIsotopes = numIsotopesDefined();
string name = toLowerCopy(trimCopy(ename));
for (int i = 0; i < numElements; i++) {
if (name == atomicWeightTable[i].fullName) {
return atomicWeightTable[i].symbol;
for (const auto& atom : atomicWeightTable) {
if (name == atom.fullName) {
return atom.symbol;
}
}
for (int i = 0; i < numIsotopes; i++) {
if (name == isotopeWeightTable[i].fullName) {
return isotopeWeightTable[i].symbol;
for (const auto& atom : isotopeWeightTable) {
if (name == atom.fullName) {
return atom.symbol;
}
}
throw CanteraError("getElementSymbol", "element not found: " + ename);
Expand All @@ -285,17 +353,15 @@ string getElementSymbol(int atomicNumber)

string getElementName(const std::string& ename)
{
int numElements = numElementsDefined();
int numIsotopes = numIsotopesDefined();
string symbol = trimCopy(ename);
for (int i = 0; i < numElements; i++) {
if (symbol == atomicWeightTable[i].symbol) {
return atomicWeightTable[i].fullName;
for (const auto& atom : atomicWeightTable) {
if (symbol == atom.symbol) {
return atom.fullName;
}
}
for (int i = 0; i < numIsotopes; i++) {
if (symbol == isotopeWeightTable[i].symbol) {
return isotopeWeightTable[i].fullName;
for (const auto& atom : isotopeWeightTable) {
if (symbol == atom.symbol) {
return atom.fullName;
}
}
throw CanteraError("getElementName", "element not found: " + ename);
Expand Down Expand Up @@ -336,12 +402,12 @@ int getAtomicNumber(const std::string& ename)

size_t numElementsDefined()
{
return sizeof(atomicWeightTable) / sizeof(struct atomicWeightData);
return atomicWeightTable.size();
}

size_t numIsotopesDefined()
{
return sizeof(isotopeWeightTable) / sizeof(struct isotopeWeightData);
return isotopeWeightTable.size();
}

}

0 comments on commit 840aea9

Please sign in to comment.