From 672b55a72f8aaafdd3c6918fc6ca02cac93e5f7e Mon Sep 17 00:00:00 2001 From: Ray Speth Date: Wed, 6 Feb 2019 19:26:43 -0500 Subject: [PATCH] Add AnyValue::getMapWhere function --- include/cantera/base/AnyMap.h | 5 +++++ interfaces/cython/cantera/_cantera.pxd | 1 + interfaces/cython/cantera/base.pyx | 22 ++++------------------ src/base/AnyMap.cpp | 14 ++++++++++++++ src/kinetics/KineticsFactory.cpp | 15 ++------------- src/thermo/IonsFromNeutralVPSSTP.cpp | 4 ++-- src/thermo/LatticeSolidPhase.cpp | 9 ++------- src/thermo/ThermoFactory.cpp | 20 ++++---------------- src/thermo/ThermoPhase.cpp | 8 ++------ test/kinetics/kineticsFromYaml.cpp | 14 ++++++-------- 10 files changed, 42 insertions(+), 70 deletions(-) diff --git a/include/cantera/base/AnyMap.h b/include/cantera/base/AnyMap.h index d533b73c5..eb20652b4 100644 --- a/include/cantera/base/AnyMap.h +++ b/include/cantera/base/AnyMap.h @@ -123,6 +123,11 @@ public: std::unordered_map asMap(const std::string& name) const; std::unordered_map asMap(const std::string& name); + //! For objects of type vector, return the item where the given key + //! has the specified value. If value is the empty string, returns the first + //! item in the list. + AnyMap& getMapWhere(const std::string& key, const std::string& value); + //! @see AnyMap::applyUnits void applyUnits(const UnitSystem& units); diff --git a/interfaces/cython/cantera/_cantera.pxd b/interfaces/cython/cantera/_cantera.pxd index 68cec9fd0..e31d19b09 100644 --- a/interfaces/cython/cantera/_cantera.pxd +++ b/interfaces/cython/cantera/_cantera.pxd @@ -55,6 +55,7 @@ cdef extern from "cantera/base/AnyMap.h" namespace "Cantera": cdef cppclass CxxAnyValue "Cantera::AnyValue": CxxAnyValue() unordered_map[string, CxxAnyMap*] asMap(string) except +translate_exception + CxxAnyMap& getMapWhere(string, string) except +translate_exception CxxAnyMap AnyMapFromYamlFile "Cantera::AnyMap::fromYamlFile" (string) except +translate_exception CxxAnyMap AnyMapFromYamlString "Cantera::AnyMap::fromYamlString" (string) except +translate_exception diff --git a/interfaces/cython/cantera/base.pyx b/interfaces/cython/cantera/base.pyx index c91e0c501..4a8277ca8 100644 --- a/interfaces/cython/cantera/base.pyx +++ b/interfaces/cython/cantera/base.pyx @@ -50,26 +50,12 @@ cdef class _SolutionBase: elif source: root = AnyMapFromYamlString(stringify(source)) - phaseNodes = root[stringify("phases")].asMap(stringify("name")) - phaseNames = [] - for item in phaseNodes: - phaseNames.append(pystr(item.first)) - - if not phaseNames: - raise ValueError("YAML document doesn't contain any phase definitions") - - if phaseid: - if phaseid in phaseNames: - phaseNode = phaseNodes[stringify(phaseid)] - else: - raise ValueError("YAML document doesn't contain" - " a phase named '{}'".format(phaseid)) - else: - phaseNode = phaseNodes[stringify(phaseNames[0])] + phaseNode = root[stringify("phases")].getMapWhere(stringify("name"), + stringify(phaseid)) # Thermo if isinstance(self, ThermoPhase): - self._thermo = newPhase(deref(phaseNode), root) + self._thermo = newPhase(phaseNode, root) self.thermo = self._thermo.get() else: self.thermo = NULL @@ -83,7 +69,7 @@ cdef class _SolutionBase: for phase in phases: # adjacent bulk phases for a surface phase v.push_back(phase.thermo) - self._kinetics = newKinetics(v, deref(phaseNode), root) + self._kinetics = newKinetics(v, phaseNode, root) self.kinetics = self._kinetics.get() else: self.kinetics = NULL diff --git a/src/base/AnyMap.cpp b/src/base/AnyMap.cpp index 582749846..a19424136 100644 --- a/src/base/AnyMap.cpp +++ b/src/base/AnyMap.cpp @@ -468,6 +468,20 @@ std::unordered_map AnyValue::asMap(const std::string& name return mapped; } +AnyMap& AnyValue::getMapWhere(const std::string& key, const std::string& value) +{ + if (value == "") { + return asVector().at(0); + } + for (auto& item : asVector()) { + if (item.hasKey(key) && item[key].asString() == value) { + return item; + } + } + throw InputFileError("AnyValue::getMapWhere", *this, + "List does not contain a map where '{}' = '{}'", key, value); +} + void AnyValue::applyUnits(const UnitSystem& units) { if (is()) { diff --git a/src/kinetics/KineticsFactory.cpp b/src/kinetics/KineticsFactory.cpp index 024ee2c46..87c570719 100644 --- a/src/kinetics/KineticsFactory.cpp +++ b/src/kinetics/KineticsFactory.cpp @@ -80,19 +80,8 @@ unique_ptr newKinetics(std::vector& phases, if (extension == "yml" || extension == "yaml") { AnyMap root = AnyMap::fromYamlFile(filename); - if (phase_name != "") { - auto phaseNodes = root["phases"].asMap("name"); - if (phaseNodes.find(phase_name) == phaseNodes.end()) { - throw CanteraError("newKinetics", - "Couldn't find phase named '{}' in file '{}'.", - phase_name, filename); - } - return newKinetics(phases, *phaseNodes[phase_name], root); - } else { - // Use the first phase definition - auto& phaseNode = root["phases"].asVector().at(0); - return newKinetics(phases, phaseNode, root); - } + AnyMap& phaseNode = root["phases"].getMapWhere("name", phase_name); + return newKinetics(phases, phaseNode, root); } else { XML_Node* root = get_XML_File(filename); XML_Node* xphase = get_XML_NameID("phase", "#"+phase_name, root); diff --git a/src/thermo/IonsFromNeutralVPSSTP.cpp b/src/thermo/IonsFromNeutralVPSSTP.cpp index 6cd8308e0..18c4a0e96 100644 --- a/src/thermo/IonsFromNeutralVPSSTP.cpp +++ b/src/thermo/IonsFromNeutralVPSSTP.cpp @@ -485,8 +485,8 @@ void IonsFromNeutralVPSSTP::initThermo() if (m_input.hasKey("neutral-phase") && m_input.hasKey("__file__")) { string neutralName = m_input["neutral-phase"].asString(); AnyMap infile = AnyMap::fromYamlFile(m_input["__file__"].asString()); - auto phaseNodes = infile["phases"].asMap("name"); - setNeutralMoleculePhase(newPhase(*phaseNodes.at(neutralName), infile)); + AnyMap& phaseNode = infile["phases"].getMapWhere("name", neutralName); + setNeutralMoleculePhase(newPhase(phaseNode, infile)); } size_t nElementsN = neutralMoleculePhase_->nElements(); diff --git a/src/thermo/LatticeSolidPhase.cpp b/src/thermo/LatticeSolidPhase.cpp index 771ad12a0..3720aeb1d 100644 --- a/src/thermo/LatticeSolidPhase.cpp +++ b/src/thermo/LatticeSolidPhase.cpp @@ -290,15 +290,10 @@ void LatticeSolidPhase::initThermo() { if (m_input.hasKey("composition") && m_input.hasKey("__file__")) { AnyMap infile = AnyMap::fromYamlFile(m_input["__file__"].asString()); - auto phaseNodes = infile["phases"].asMap("name"); compositionMap composition = m_input["composition"].asMap(); for (auto& item : composition) { - if (phaseNodes.count(item.first)) { - addLattice(newPhase(*phaseNodes.at(item.first), infile)); - } else { - throw CanteraError("LatticeSolidPhase::initThermo", - "Could not find component phase named '{}'.", item.first); - } + AnyMap& node = infile["phases"].getMapWhere("name", item.first); + addLattice(newPhase(node, infile)); } setLatticeStoichiometry(composition); } diff --git a/src/thermo/ThermoFactory.cpp b/src/thermo/ThermoFactory.cpp index 4ad970ff7..66ee17954 100644 --- a/src/thermo/ThermoFactory.cpp +++ b/src/thermo/ThermoFactory.cpp @@ -128,22 +128,10 @@ ThermoPhase* newPhase(const std::string& infile, std::string id) if (extension == "yml" || extension == "yaml") { AnyMap root = AnyMap::fromYamlFile(infile); - if (id != "") { - auto phases = root["phases"].asMap("name"); - if (phases.find(id) == phases.end()) { - throw CanteraError("newPhase", - "Couldn't find phase named '{}' in file '{}'.", id, infile); - } - unique_ptr t(newThermoPhase(phases[id]->at("thermo").asString())); - setupPhase(*t, *phases[id], root); - return t.release(); - } else { - // Use the first phase definition - auto& phase = root["phases"].asVector().at(0); - unique_ptr t(newThermoPhase(phase["thermo"].asString())); - setupPhase(*t, phase, root); - return t.release(); - } + AnyMap& phase = root["phases"].getMapWhere("name", id); + unique_ptr t(newThermoPhase(phase["thermo"].asString())); + setupPhase(*t, phase, root); + return t.release(); } else { XML_Node* root = get_XML_File(infile); XML_Node* xphase = get_XML_NameID("phase", "#"+id, root); diff --git a/src/thermo/ThermoPhase.cpp b/src/thermo/ThermoPhase.cpp index 68b638bc9..3b6a6cb7a 100644 --- a/src/thermo/ThermoPhase.cpp +++ b/src/thermo/ThermoPhase.cpp @@ -685,12 +685,8 @@ void ThermoPhase::initThermoFile(const std::string& inputFile, if (extension == "yml" || extension == "yaml") { AnyMap root = AnyMap::fromYamlFile(inputFile); - auto phases = root["phases"].asMap("name"); - if (phases.find(id) == phases.end()) { - throw CanteraError("newPhase", - "Couldn't find phase named '{}' in file '{}'.", id, inputFile); - } - setupPhase(*this, *phases[id], root); + auto& phase = root["phases"].getMapWhere("name", id); + setupPhase(*this, phase, root); } else { XML_Node* fxml = get_XML_File(inputFile); XML_Node* fxml_phase = findXMLPhase(fxml, id); diff --git a/test/kinetics/kineticsFromYaml.cpp b/test/kinetics/kineticsFromYaml.cpp index f6691f7d9..8d8259e7e 100644 --- a/test/kinetics/kineticsFromYaml.cpp +++ b/test/kinetics/kineticsFromYaml.cpp @@ -174,11 +174,10 @@ TEST(Reaction, ChebyshevFromYaml) TEST(Kinetics, GasKineticsFromYaml1) { AnyMap infile = AnyMap::fromYamlFile("ideal-gas.yaml"); - auto phaseNodes = infile["phases"].asMap("name"); - auto phaseNode = phaseNodes.at("simple-kinetics"); - shared_ptr thermo = newPhase(*phaseNode, infile); + auto& phaseNode = infile["phases"].getMapWhere("name", "simple-kinetics"); + shared_ptr thermo = newPhase(phaseNode, infile); std::vector phases{thermo.get()}; - auto kin = newKinetics(phases, *phaseNode, infile); + auto kin = newKinetics(phases, phaseNode, infile); EXPECT_EQ(kin->nReactions(), (size_t) 2); const auto& R = kin->reaction(0); EXPECT_EQ(R->reactants.at("NO"), 1); @@ -191,11 +190,10 @@ TEST(Kinetics, GasKineticsFromYaml1) TEST(Kinetics, GasKineticsFromYaml2) { AnyMap infile = AnyMap::fromYamlFile("ideal-gas.yaml"); - auto phaseNodes = infile["phases"].asMap("name"); - auto phaseNode = phaseNodes.at("remote-kinetics"); - shared_ptr thermo = newPhase(*phaseNode, infile); + auto& phaseNode = infile["phases"].getMapWhere("name", "remote-kinetics"); + shared_ptr thermo = newPhase(phaseNode, infile); std::vector phases{thermo.get()}; - auto kin = newKinetics(phases, *phaseNode, infile); + auto kin = newKinetics(phases, phaseNode, infile); EXPECT_EQ(kin->nReactions(), (size_t) 3); }