diff --git a/include/cantera/thermo/Phase.h b/include/cantera/thermo/Phase.h index 48635dc4c0..0d5d4008ae 100644 --- a/include/cantera/thermo/Phase.h +++ b/include/cantera/thermo/Phase.h @@ -703,6 +703,19 @@ class Phase */ virtual void modifySpecies(size_t k, shared_ptr 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 findIsomers(const compositionMap& compMap) 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. diff --git a/interfaces/cython/cantera/_cantera.pxd b/interfaces/cython/cantera/_cantera.pxd index 67939086e2..407eddc5bf 100644 --- a/interfaces/cython/cantera/_cantera.pxd +++ b/interfaces/cython/cantera/_cantera.pxd @@ -183,6 +183,8 @@ 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 double molecularWeight(size_t) except +translate_exception double meanMolecularWeight() diff --git a/interfaces/cython/cantera/thermo.pyx b/interfaces/cython/cantera/thermo.pyx index aa5dad5eb1..7d333e2944 100644 --- a/interfaces/cython/cantera/thermo.pyx +++ b/interfaces/cython/cantera/thermo.pyx @@ -524,6 +524,22 @@ 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*. + """ + + assert isinstance(comp, dict), 'Composition needs to be specified as dictionary' + iso = self.thermo.findIsomers(comp_map(comp)) + + return [pystr(b) for b in iso] + def n_atoms(self, species, element): """ Number of atoms of element *element* in species *species*. The element diff --git a/src/thermo/Phase.cpp b/src/thermo/Phase.cpp index 2c18552e38..af50f1634b 100644 --- a/src/thermo/Phase.cpp +++ b/src/thermo/Phase.cpp @@ -852,6 +852,35 @@ void Phase::modifySpecies(size_t k, shared_ptr 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; + } else { + throw CanteraError("Phase::addSpeciesAlias", + "Unable to add alias '{}' " + "(original species '{}' not found).", alias, name); + } +} + +vector Phase::findIsomers(const compositionMap& compMap) const +{ + vector isomerNames; + + for (const auto& k : m_species) { + if (k.second->composition == compMap) { + isomerNames.emplace_back(k.first); + } + } + + return isomerNames; +} + shared_ptr Phase::species(const std::string& name) const { size_t k = speciesIndex(name);