Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add species alias #714

Merged
merged 3 commits into from
Oct 30, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions include/cantera/thermo/Phase.h
Original file line number Diff line number Diff line change
Expand Up @@ -703,6 +703,24 @@ class Phase
*/
virtual void modifySpecies(size_t k, shared_ptr<Species> spec);

//! Add a species alias (i.e. user-defined alternative species name).
//! Aliases are case-sensitive.
//! @param name original species name std::string.
//! @param alias alternate name std::string.
//! @return `true` if the alias was successfully added
//! (i.e. the original species name is found)
void addSpeciesAlias(const std::string& name, const std::string& alias);

//! Return a vector with isomers names matching a given composition map
//! @param compMap compositionMap of the species.
//! @return A vector of species names for matching species.
virtual std::vector<std::string> findIsomers(const compositionMap& compMap) const;

//! Return a vector with isomers names matching a given composition string
//! @param comp String containing a composition map
//! @return A vector of species names for matching species.
virtual std::vector<std::string> findIsomers(const std::string& comp) const;

//! Return the Species object for the named species. Changes to this object
//! do not affect the ThermoPhase object until the #modifySpecies function
//! is called.
Expand Down
3 changes: 3 additions & 0 deletions interfaces/cython/cantera/_cantera.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,9 @@ cdef extern from "cantera/thermo/ThermoPhase.h" namespace "Cantera":
void getAtoms(size_t, double*) except +translate_exception
cbool caseSensitiveSpecies()
void setCaseSensitiveSpecies(cbool)
void addSpeciesAlias(string, string) except +translate_exception
vector[string] findIsomers(Composition&) except +translate_exception
vector[string] findIsomers(string) except +translate_exception

double molecularWeight(size_t) except +translate_exception
double meanMolecularWeight()
Expand Down
21 changes: 21 additions & 0 deletions interfaces/cython/cantera/test/test_thermo.py
Original file line number Diff line number Diff line change
Expand Up @@ -1140,6 +1140,27 @@ def test_modify_thermo_invalid(self):
with self.assertRaisesRegex(ct.CanteraError, 'modifySpecies'):
self.gas.modify_species(self.gas.species_index('H2'), copy)

def test_alias(self):
self.gas.add_species_alias('H2', 'hydrogen')
self.assertTrue(self.gas.species_index('hydrogen') == 0)
self.gas.X = 'hydrogen:.5, O2:.5'
self.assertNear(self.gas.X[0], 0.5)
with self.assertRaisesRegex(ct.CanteraError, 'Invalid alias'):
self.gas.add_species_alias('H2', 'O2')
with self.assertRaisesRegex(ct.CanteraError, 'Unable to add alias'):
self.gas.add_species_alias('spam', 'eggs')

def test_isomers(self):
gas = ct.Solution('nDodecane_Reitz.yaml')
iso = gas.find_isomers({'C':4, 'H':9, 'O':2})
self.assertTrue(len(iso) == 2)
iso = gas.find_isomers('C:4, H:9, O:2')
self.assertTrue(len(iso) == 2)
iso = gas.find_isomers({'C':7, 'H':15})
self.assertTrue(len(iso) == 1)
iso = gas.find_isomers({'C':7, 'H':16})
self.assertTrue(len(iso) == 0)


class TestSpeciesThermo(utilities.CanteraTest):
h2o_coeffs = [
Expand Down
20 changes: 20 additions & 0 deletions interfaces/cython/cantera/thermo.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -524,6 +524,26 @@ cdef class ThermoPhase(_SolutionBase):
if self.kinetics:
self.kinetics.invalidateCache()

def add_species_alias(self, name, alias):
"""
Add the alternate species name *alias* for an original species *name*.
"""
self.thermo.addSpeciesAlias(stringify(name), stringify(alias))

def find_isomers(self, comp):
"""
Find species/isomers matching a composition specified by *comp*.
"""

if isinstance(comp, dict):
iso = self.thermo.findIsomers(comp_map(comp))
elif isinstance(comp, (str, bytes)):
iso = self.thermo.findIsomers(stringify(comp))
else:
raise CanteraError('Invalid composition')

return [pystr(b) for b in iso]

def n_atoms(self, species, element):
"""
Number of atoms of element *element* in species *species*. The element
Expand Down
34 changes: 34 additions & 0 deletions src/thermo/Phase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -852,6 +852,40 @@ void Phase::modifySpecies(size_t k, shared_ptr<Species> spec)
invalidateCache();
}

void Phase::addSpeciesAlias(const std::string& name, const std::string& alias)
{
if (speciesIndex(alias) != npos) {
throw CanteraError("Phase::addSpeciesAlias",
"Invalid alias '{}': species already exists", alias);
}
size_t k = speciesIndex(name);
if (k != npos) {
m_speciesIndices[alias] = k;
ischoegl marked this conversation as resolved.
Show resolved Hide resolved
} else {
throw CanteraError("Phase::addSpeciesAlias",
"Unable to add alias '{}' "
"(original species '{}' not found).", alias, name);
}
}

vector<std::string> Phase::findIsomers(const compositionMap& compMap) const
{
vector<std::string> isomerNames;

for (const auto& k : m_species) {
if (k.second->composition == compMap) {
isomerNames.emplace_back(k.first);
}
}

return isomerNames;
}

vector<std::string> Phase::findIsomers(const std::string& comp) const
{
return findIsomers(parseCompString(comp));
}

shared_ptr<Species> Phase::species(const std::string& name) const
{
size_t k = speciesIndex(name);
Expand Down