diff --git a/include/cantera/base/FactoryBase.h b/include/cantera/base/FactoryBase.h index a6ea596e6f..511ab1cdc2 100644 --- a/include/cantera/base/FactoryBase.h +++ b/include/cantera/base/FactoryBase.h @@ -7,6 +7,8 @@ #include #include +#include +#include "cantera/base/ctexceptions.h" namespace Cantera { @@ -53,6 +55,36 @@ class FactoryBase //! statically held list of Factories. static std::vector s_vFactoryRegistry; }; + +//! Factory class that supports registering functions to create objects +//! +//! Template arguments for the class are the base type created by the factory, +//! followed by the types of any arguments which need to be passed to the +//! functions used to create objects, e.g. arguments to the constructor. +template +class Factory : public FactoryBase { +public: + virtual ~Factory() {} + + //! Create an object using the object construction function corresponding to + //! "name" and the provided constructor arguments + T* create(const std::string& name, Args... args) { + try { + return m_creators.at(name)(args...); + } catch (std::out_of_range&) { + throw CanteraError("Factory::create", "No such type: '{}'", name); + } + } + + //! Register a new object construction function + void reg(const std::string& name, std::function f) { + m_creators[name] = f; + } + +protected: + std::unordered_map> m_creators; +}; + } #endif diff --git a/include/cantera/kinetics/FalloffFactory.h b/include/cantera/kinetics/FalloffFactory.h index d9a91290ea..263d2bf380 100644 --- a/include/cantera/kinetics/FalloffFactory.h +++ b/include/cantera/kinetics/FalloffFactory.h @@ -25,7 +25,7 @@ namespace Cantera * * @ingroup falloffGroup */ -class FalloffFactory : public FactoryBase +class FalloffFactory : public Factory { public: /** @@ -64,7 +64,7 @@ class FalloffFactory : public FactoryBase static FalloffFactory* s_factory; //! default constructor, which is defined as private - FalloffFactory() {} + FalloffFactory(); //! Mutex for use when calling the factory static std::mutex falloff_mutex; diff --git a/include/cantera/kinetics/KineticsFactory.h b/include/cantera/kinetics/KineticsFactory.h index 92bf2b1523..ffd476b79b 100644 --- a/include/cantera/kinetics/KineticsFactory.h +++ b/include/cantera/kinetics/KineticsFactory.h @@ -25,7 +25,7 @@ class UnknownKineticsModel : public CanteraError /** * Factory for kinetics managers. */ -class KineticsFactory : public FactoryBase +class KineticsFactory : public Factory { public: static KineticsFactory* factory() { @@ -70,7 +70,7 @@ class KineticsFactory : public FactoryBase private: static KineticsFactory* s_factory; - KineticsFactory() {} + KineticsFactory(); static std::mutex kinetics_mutex; }; diff --git a/include/cantera/thermo/ThermoFactory.h b/include/cantera/thermo/ThermoFactory.h index a025d31889..1f8fe5bdda 100644 --- a/include/cantera/thermo/ThermoFactory.h +++ b/include/cantera/thermo/ThermoFactory.h @@ -49,7 +49,7 @@ class UnknownThermoPhaseModel : public CanteraError * This class keeps a list of the known ThermoPhase classes, and is * used to create new instances of these classes. */ -class ThermoFactory : public FactoryBase +class ThermoFactory : public Factory { public: //! Static function that creates a static instance of the factory. @@ -82,7 +82,7 @@ class ThermoFactory : public FactoryBase static ThermoFactory* s_factory; //! Private constructors prevents usage - ThermoFactory() {}; + ThermoFactory(); //! Decl for locking mutex for thermo factory singleton static std::mutex thermo_mutex; @@ -102,7 +102,7 @@ inline ThermoPhase* newThermoPhase(const std::string& model, if (f == 0) { f = ThermoFactory::factory(); } - return f->newThermoPhase(model); + return f->create(model); } //! Translate the eosType id into a string diff --git a/include/cantera/transport/TransportBase.h b/include/cantera/transport/TransportBase.h index f937a97fec..d7fe22242e 100644 --- a/include/cantera/transport/TransportBase.h +++ b/include/cantera/transport/TransportBase.h @@ -709,9 +709,7 @@ class Transport * specification of the collision integrals. defaults to no. * @param log_level Defaults to zero, no logging */ - virtual void init(thermo_t* thermo, int mode=0, int log_level=0) { - throw NotImplementedError("Transport::init"); - } + virtual void init(thermo_t* thermo, int mode=0, int log_level=0) {} //! Called by TransportFactory to set parameters. /*! diff --git a/include/cantera/transport/TransportFactory.h b/include/cantera/transport/TransportFactory.h index 565723e493..d4b98bc73f 100644 --- a/include/cantera/transport/TransportFactory.h +++ b/include/cantera/transport/TransportFactory.h @@ -26,7 +26,7 @@ namespace Cantera * * @ingroup tranprops */ -class TransportFactory : public FactoryBase +class TransportFactory : public Factory { public: //! Return a pointer to a TransportFactory instance. @@ -104,8 +104,7 @@ class TransportFactory : public FactoryBase * @param thermo ThermoPhase object * @param log_level log level */ - virtual Transport* - newTransport(thermo_t* thermo, int log_level=0); + virtual Transport* newTransport(thermo_t* thermo, int log_level=0); //! Initialize an existing transport manager for liquid phase /*! @@ -242,6 +241,9 @@ class TransportFactory : public FactoryBase //! Mapping between between the string name for a //! liquid mixture transport property model and the integer name. std::map m_LTImodelMap; + + //! Models included in this map are initialized in CK compatibility mode + std::map m_CK_mode; }; //! Create a new transport manager instance. diff --git a/include/cantera/zeroD/ReactorFactory.h b/include/cantera/zeroD/ReactorFactory.h index 9626689d2c..27ef227974 100644 --- a/include/cantera/zeroD/ReactorFactory.h +++ b/include/cantera/zeroD/ReactorFactory.h @@ -11,7 +11,7 @@ namespace Cantera { -class ReactorFactory : FactoryBase +class ReactorFactory : public Factory { public: static ReactorFactory* factory() { @@ -38,7 +38,7 @@ class ReactorFactory : FactoryBase private: static ReactorFactory* s_factory; static std::mutex reactor_mutex; - ReactorFactory() {} + ReactorFactory(); }; inline ReactorBase* newReactor(const std::string& model, diff --git a/src/kinetics/FalloffFactory.cpp b/src/kinetics/FalloffFactory.cpp index b40fdc2422..83be16e669 100644 --- a/src/kinetics/FalloffFactory.cpp +++ b/src/kinetics/FalloffFactory.cpp @@ -12,22 +12,22 @@ namespace Cantera FalloffFactory* FalloffFactory::s_factory = 0; std::mutex FalloffFactory::falloff_mutex; +FalloffFactory::FalloffFactory() +{ + reg("Simple", []() { return new Falloff(); }); + reg("Troe", []() { return new Troe(); }); + reg("SRI", []() { return new SRI(); }); +} + Falloff* FalloffFactory::newFalloff(int type, const vector_fp& c) { - Falloff* f; - switch (type) { - case SIMPLE_FALLOFF: - f = new Falloff(); - break; - case TROE_FALLOFF: - f = new Troe(); - break; - case SRI_FALLOFF: - f = new SRI(); - break; - default: - return 0; - } + static const std::unordered_map types { + {SIMPLE_FALLOFF, "Simple"}, + {TROE_FALLOFF, "Troe"}, + {SRI_FALLOFF, "SRI"} + }; + + Falloff* f = create(types.at(type)); f->init(c); return f; } diff --git a/src/kinetics/KineticsFactory.cpp b/src/kinetics/KineticsFactory.cpp index ebcc446887..7b9921388b 100644 --- a/src/kinetics/KineticsFactory.cpp +++ b/src/kinetics/KineticsFactory.cpp @@ -37,22 +37,17 @@ Kinetics* KineticsFactory::newKinetics(XML_Node& phaseData, return k; } +KineticsFactory::KineticsFactory() { + reg("none", []() { return new Kinetics(); }); + reg("gaskinetics", []() { return new GasKinetics(); }); + reg("interface", []() { return new InterfaceKinetics(); }); + reg("edge", []() { return new EdgeKinetics(); }); + reg("aqueouskinetics", []() { return new AqueousKinetics(); }); +} + Kinetics* KineticsFactory::newKinetics(const string& model) { - string lcmodel = lowercase(model); - if (lcmodel == "none") { - return new Kinetics(); - } else if (lcmodel == "gaskinetics") { - return new GasKinetics(); - } else if (lcmodel == "interface") { - return new InterfaceKinetics(); - } else if (lcmodel == "edge") { - return new EdgeKinetics(); - } else if (lcmodel == "aqueouskinetics") { - return new AqueousKinetics(); - } else { - throw UnknownKineticsModel("KineticsFactory::newKinetics", model); - } + return create(lowercase(model)); } } diff --git a/src/thermo/ThermoFactory.cpp b/src/thermo/ThermoFactory.cpp index de78f59c01..6b4443646c 100644 --- a/src/thermo/ThermoFactory.cpp +++ b/src/thermo/ThermoFactory.cpp @@ -77,71 +77,39 @@ static int _itypes[] = {cIdealGas, cIncompressible, cRedlichKwongMFTP, cRedlichKwongMFTP, cMaskellSolidSolnPhase }; -ThermoPhase* ThermoFactory::newThermoPhase(const std::string& model) +ThermoFactory::ThermoFactory() { - int ieos=-1; - - for (int n = 0; n < ntypes; n++) { - if (model == _types[n]) { - ieos = _itypes[n]; - break; - } - } + reg("IdealGas", []() { return new IdealGasPhase(); }); + reg("Incompressible", []() { return new ConstDensityThermo(); }); + reg("Surface", []() { return new SurfPhase(); }); + reg("Edge", []() { return new EdgePhase(); }); + reg("Metal", []() { return new MetalPhase(); }); + reg("StoichSubstance", []() { return new StoichSubstance(); }); + reg("PureFluid", []() { return new PureFluidPhase(); }); + reg("LatticeSolid", []() { return new LatticeSolidPhase(); }); + reg("Lattice", []() { return new LatticePhase(); }); + reg("HMW", []() { return new HMWSoln(); }); + reg("IdealSolidSolution", []() { return new IdealSolidSolnPhase(); }); + reg("DebyeHuckel", []() { return new DebyeHuckel(); }); + reg("IdealMolalSolution", []() { return new IdealMolalSoln(); }); + reg("IdealGasVPSS", []() { return new IdealSolnGasVPSS(); }); + reg("IdealSolnVPSS", []() { return new IdealSolnGasVPSS(); }); + reg("MineralEQ3", []() { return new MineralEQ3(); }); + reg("MetalSHEelectrons", []() { return new MetalSHEelectrons(); }); + reg("Margules", []() { return new MargulesVPSSTP(); }); + reg("PhaseCombo_Interaction", []() { return new PhaseCombo_Interaction(); }); + reg("IonsFromNeutralMolecule", []() { return new IonsFromNeutralVPSSTP(); }); + reg("FixedChemPot", []() { return new FixedChemPotSSTP(); }); + reg("MolarityIonicVPSSTP", []() { return new MolarityIonicVPSSTP(); }); + reg("Redlich-Kister", []() { return new RedlichKisterVPSSTP(); }); + reg("RedlichKwong", []() { return new RedlichKwongMFTP(); }); + reg("RedlichKwongMFTP", []() { return new RedlichKwongMFTP(); }); + reg("MaskellSolidSolnPhase", []() { return new MaskellSolidSolnPhase(); }); +} - switch (ieos) { - case cIdealGas: - return new IdealGasPhase; - case cIncompressible: - return new ConstDensityThermo; - case cSurf: - return new SurfPhase; - case cEdge: - return new EdgePhase; - case cIdealSolidSolnPhase: - return new IdealSolidSolnPhase(); - case cMargulesVPSSTP: - return new MargulesVPSSTP(); - case cRedlichKisterVPSSTP: - return new RedlichKisterVPSSTP(); - case cMolarityIonicVPSSTP: - return new MolarityIonicVPSSTP(); - case cPhaseCombo_Interaction: - return new PhaseCombo_Interaction(); - case cIonsFromNeutral: - return new IonsFromNeutralVPSSTP(); - case cMetal: - return new MetalPhase; - case cStoichSubstance: - return new StoichSubstance; - case cFixedChemPot: - return new FixedChemPotSSTP; - case cMineralEQ3: - return new MineralEQ3(); - case cMetalSHEelectrons: - return new MetalSHEelectrons(); - case cLatticeSolid: - return new LatticeSolidPhase; - case cLattice: - return new LatticePhase; - case cPureFluid: - return new PureFluidPhase; - case cRedlichKwongMFTP: - return new RedlichKwongMFTP; - case cHMW: - return new HMWSoln; - case cDebyeHuckel: - return new DebyeHuckel; - case cIdealMolalSoln: - return new IdealMolalSoln; - case cVPSS_IdealGas: - return new IdealSolnGasVPSS; - case cIdealSolnGasVPSS_iscv: - return new IdealSolnGasVPSS; - case cMaskellSolidSolnPhase: - return new MaskellSolidSolnPhase; - default: - throw UnknownThermoPhaseModel("ThermoFactory::newThermoPhase", model); - } +ThermoPhase* ThermoFactory::newThermoPhase(const std::string& model) +{ + return create(model); } std::string eosTypeString(int ieos, int length) diff --git a/src/thermo/VPSSMgrFactory.cpp b/src/thermo/VPSSMgrFactory.cpp index ac25db771b..bd1761ca59 100644 --- a/src/thermo/VPSSMgrFactory.cpp +++ b/src/thermo/VPSSMgrFactory.cpp @@ -183,6 +183,25 @@ static void getVPSSMgrTypes(std::vector & spDataNodeList, } } +VPSSMgrFactory::VPSSMgrFactory() +{ + reg("idealgas", + [] (VPStandardStateTP* tp, MultiSpeciesThermo* st) { + return new VPSSMgr_IdealGas(tp, st); }); + reg("constvol", + [] (VPStandardStateTP* tp, MultiSpeciesThermo* st) { + return new VPSSMgr_ConstVol(tp, st); }); + reg("water_constvol", + [] (VPStandardStateTP* tp, MultiSpeciesThermo* st) { + return new VPSSMgr_Water_ConstVol(tp, st); }); + reg("water_hkft", + [] (VPStandardStateTP* tp, MultiSpeciesThermo* st) { + return new VPSSMgr_Water_HKFT(tp, st); }); + reg("general", + [] (VPStandardStateTP* tp, MultiSpeciesThermo* st) { + return new VPSSMgr_General(tp, st); }); +} + void VPSSMgrFactory::deleteFactory() { std::unique_lock lock(vpss_species_thermo_mutex); @@ -230,7 +249,7 @@ VPSSMgr* VPSSMgrFactory::newVPSSMgr(VPStandardStateTP* vp_ptr, } if (thermoNode.hasChild("variablePressureStandardStateManager")) { const XML_Node& vpssNode = thermoNode.child("variablePressureStandardStateManager"); - vpssManager = vpssNode["model"]; + vpssManager = lowercase(vpssNode["model"]); } } @@ -241,8 +260,7 @@ VPSSMgr* VPSSMgrFactory::newVPSSMgr(VPStandardStateTP* vp_ptr, // Next, if we have specific directions, use them to get the VPSSSMgr object // and return immediately if (vpssManager != "") { - VPSSMgr_enumType type = VPSSMgr_StringConversion(vpssManager); - return newVPSSMgr(type, vp_ptr); + return create(vpssManager, vp_ptr, spth); } // Handle special cases based on the VPStandardState types @@ -292,27 +310,15 @@ VPSSMgr* VPSSMgrFactory::newVPSSMgr(VPStandardStateTP* vp_ptr, VPSSMgr* VPSSMgrFactory::newVPSSMgr(VPSSMgr_enumType type, VPStandardStateTP* vp_ptr) { + static unordered_map types { + {cVPSSMGR_IDEALGAS, "idealgas"}, + {cVPSSMGR_CONSTVOL, "constvol"}, + {cVPSSMGR_WATER_CONSTVOL, "water_constvol"}, + {cVPSSMGR_WATER_HKFT, "water_hkft"}, + {cVPSSMGR_GENERAL, "general"} + }; MultiSpeciesThermo& spthermoRef = vp_ptr->speciesThermo(); - switch (type) { - case cVPSSMGR_IDEALGAS: - return new VPSSMgr_IdealGas(vp_ptr, &spthermoRef); - case cVPSSMGR_CONSTVOL: - return new VPSSMgr_ConstVol(vp_ptr, &spthermoRef); - case cVPSSMGR_PUREFLUID: - throw CanteraError("VPSSMgrFactory::newVPSSMgr", - "unimplemented"); - case cVPSSMGR_WATER_CONSTVOL: - return new VPSSMgr_Water_ConstVol(vp_ptr, &spthermoRef); - case cVPSSMGR_WATER_HKFT: - return new VPSSMgr_Water_HKFT(vp_ptr, &spthermoRef); - case cVPSSMGR_GENERAL: - return new VPSSMgr_General(vp_ptr, &spthermoRef); - case cVPSSMGR_UNDEF: - default: - throw CanteraError("VPSSMgrFactory::newVPSSMgr", - "Specified VPSSMgr model {} does not match any known type.", type); - return 0; - } + return create(types.at(type), vp_ptr, &spthermoRef); } // I don't think this is currently used diff --git a/src/thermo/VPSSMgrFactory.h b/src/thermo/VPSSMgrFactory.h index f1ab751716..85dc22ba04 100644 --- a/src/thermo/VPSSMgrFactory.h +++ b/src/thermo/VPSSMgrFactory.h @@ -59,7 +59,7 @@ class UnknownVPSSMgrModel: public CanteraError * * @ingroup mgrpdssthermocalc */ -class VPSSMgrFactory : public FactoryBase +class VPSSMgrFactory : public Factory { public: //! Static method to return an instance of this class @@ -131,7 +131,7 @@ class VPSSMgrFactory : public FactoryBase //! Constructor. This is made private, so that only the static //! method factory() can instantiate the class. - VPSSMgrFactory() {} + VPSSMgrFactory(); }; ////////////////////// Convenience functions //////////////////// diff --git a/src/transport/TransportFactory.cpp b/src/transport/TransportFactory.cpp index 066b51cb62..5b10703d2a 100644 --- a/src/transport/TransportFactory.cpp +++ b/src/transport/TransportFactory.cpp @@ -41,6 +41,16 @@ class TransportDBError : public CanteraError TransportFactory::TransportFactory() { + reg("", []() { return new Transport(); }); + reg("None", []() { return new Transport(); }); + reg("Mix", []() { return new MixTransport(); }); + reg("Multi", []() { return new MultiTransport(); }); + reg("CK_Mix", []() { return new MixTransport(); }); + reg("CK_Multi", []() { return new MultiTransport(); }); + reg("HighP", []() { return new HighPressureGasTransport(); }); + m_CK_mode["CK_Mix"] = true; + m_CK_mode["CK_Multi"] = true; + m_models["Mix"] = cMixtureAveraged; m_models["Multi"] = cMulticomponent; m_models["Solid"] = cSolidTransport; @@ -173,39 +183,12 @@ LiquidTranInteraction* TransportFactory::newLTI(const XML_Node& trNode, Transport* TransportFactory::newTransport(const std::string& transportModel, thermo_t* phase, int log_level, int ndim) { - if (transportModel == "") { - return new Transport; - } - vector_fp state; Transport* tr = 0, *gastr = 0; DustyGasTransport* dtr = 0; phase->saveState(state); switch (m_models[transportModel]) { - case None: - tr = new Transport; - break; - case cMulticomponent: - tr = new MultiTransport; - tr->init(phase, 0, log_level); - break; - case CK_Multicomponent: - tr = new MultiTransport; - tr->init(phase, CK_Mode, log_level); - break; - case cMixtureAveraged: - tr = new MixTransport; - tr->init(phase, 0, log_level); - break; - case CK_MixtureAveraged: - tr = new MixTransport; - tr->init(phase, CK_Mode, log_level); - break; - case cHighP: - tr = new HighPressureGasTransport; - tr->init(phase, 0, log_level); - break; case cSolidTransport: tr = new SolidTransport; initSolidTransport(tr, phase, log_level); @@ -229,7 +212,8 @@ Transport* TransportFactory::newTransport(const std::string& transportModel, tr->setThermo(*phase); break; default: - throw CanteraError("newTransport","unknown transport model: " + transportModel); + tr = create(transportModel); + tr->init(phase, m_CK_mode[transportModel], log_level); } phase->restoreState(state); return tr; diff --git a/src/zeroD/ReactorFactory.cpp b/src/zeroD/ReactorFactory.cpp index 0b96b4f190..f96379c31c 100644 --- a/src/zeroD/ReactorFactory.cpp +++ b/src/zeroD/ReactorFactory.cpp @@ -17,50 +17,39 @@ namespace Cantera ReactorFactory* ReactorFactory::s_factory = 0; std::mutex ReactorFactory::reactor_mutex; -static int ntypes = 6; -static string _types[] = {"Reservoir", "Reactor", "ConstPressureReactor", - "FlowReactor", "IdealGasReactor", - "IdealGasConstPressureReactor" - }; - -// these constants are defined in ReactorBase.h -static int _itypes[] = {ReservoirType, ReactorType, ConstPressureReactorType, - FlowReactorType, IdealGasReactorType, - IdealGasConstPressureReactorType - }; +ReactorFactory::ReactorFactory() +{ + reg("Reservoir", []() { return new Reservoir(); }); + reg("Reactor", []() { return new Reactor(); }); + reg("ConstPressureReactor", []() { return new ConstPressureReactor(); }); + reg("FlowReactor", []() { return new FlowReactor(); }); + reg("IdealGasReactor", []() { return new IdealGasReactor(); }); + reg("IdealGasConstPressureReactor", []() { return new IdealGasConstPressureReactor(); }); +} ReactorBase* ReactorFactory::newReactor(const std::string& reactorType) { - int ir=-1; - for (int n = 0; n < ntypes; n++) { - if (reactorType == _types[n]) { - ir = _itypes[n]; - } - } - return newReactor(ir); + return create(reactorType); } ReactorBase* ReactorFactory::newReactor(int ir) { - switch (ir) { - case ReservoirType: - return new Reservoir(); - case ReactorType: - return new Reactor(); - case FlowReactorType: - return new FlowReactor(); - case ConstPressureReactorType: - return new ConstPressureReactor(); - case IdealGasReactorType: - return new IdealGasReactor(); - case IdealGasConstPressureReactorType: - return new IdealGasConstPressureReactor(); - default: + static const unordered_map types { + {ReservoirType, "Reservoir"}, + {ReactorType, "Reactor"}, + {ConstPressureReactorType, "ConstPressureReactor"}, + {FlowReactorType, "FlowReactor"}, + {IdealGasReactorType, "IdealGasReactor"}, + {IdealGasConstPressureReactorType, "IdealGasConstPressureReactor"} + }; + + try { + return create(types.at(ir)); + } catch (out_of_range&) { throw CanteraError("ReactorFactory::newReactor", "unknown reactor type!"); } - return 0; } }