Introduce basic registration capabilities for factories

This commit is contained in:
Ray Speth 2016-07-04 15:59:29 -04:00
parent 64bb049647
commit f985169e93
14 changed files with 166 additions and 192 deletions

View file

@ -7,6 +7,8 @@
#include <vector> #include <vector>
#include <mutex> #include <mutex>
#include <unordered_map>
#include "cantera/base/ctexceptions.h"
namespace Cantera namespace Cantera
{ {
@ -53,6 +55,36 @@ private:
//! statically held list of Factories. //! statically held list of Factories.
static std::vector<FactoryBase*> s_vFactoryRegistry; static std::vector<FactoryBase*> 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 T, typename ... Args>
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<T*(Args...)> f) {
m_creators[name] = f;
}
protected:
std::unordered_map<std::string, std::function<T*(Args...)>> m_creators;
};
} }
#endif #endif

View file

@ -25,7 +25,7 @@ namespace Cantera
* *
* @ingroup falloffGroup * @ingroup falloffGroup
*/ */
class FalloffFactory : public FactoryBase class FalloffFactory : public Factory<Falloff>
{ {
public: public:
/** /**
@ -64,7 +64,7 @@ private:
static FalloffFactory* s_factory; static FalloffFactory* s_factory;
//! default constructor, which is defined as private //! default constructor, which is defined as private
FalloffFactory() {} FalloffFactory();
//! Mutex for use when calling the factory //! Mutex for use when calling the factory
static std::mutex falloff_mutex; static std::mutex falloff_mutex;

View file

@ -25,7 +25,7 @@ public:
/** /**
* Factory for kinetics managers. * Factory for kinetics managers.
*/ */
class KineticsFactory : public FactoryBase class KineticsFactory : public Factory<Kinetics>
{ {
public: public:
static KineticsFactory* factory() { static KineticsFactory* factory() {
@ -70,7 +70,7 @@ public:
private: private:
static KineticsFactory* s_factory; static KineticsFactory* s_factory;
KineticsFactory() {} KineticsFactory();
static std::mutex kinetics_mutex; static std::mutex kinetics_mutex;
}; };

View file

@ -49,7 +49,7 @@ public:
* This class keeps a list of the known ThermoPhase classes, and is * This class keeps a list of the known ThermoPhase classes, and is
* used to create new instances of these classes. * used to create new instances of these classes.
*/ */
class ThermoFactory : public FactoryBase class ThermoFactory : public Factory<ThermoPhase>
{ {
public: public:
//! Static function that creates a static instance of the factory. //! Static function that creates a static instance of the factory.
@ -82,7 +82,7 @@ private:
static ThermoFactory* s_factory; static ThermoFactory* s_factory;
//! Private constructors prevents usage //! Private constructors prevents usage
ThermoFactory() {}; ThermoFactory();
//! Decl for locking mutex for thermo factory singleton //! Decl for locking mutex for thermo factory singleton
static std::mutex thermo_mutex; static std::mutex thermo_mutex;
@ -102,7 +102,7 @@ inline ThermoPhase* newThermoPhase(const std::string& model,
if (f == 0) { if (f == 0) {
f = ThermoFactory::factory(); f = ThermoFactory::factory();
} }
return f->newThermoPhase(model); return f->create(model);
} }
//! Translate the eosType id into a string //! Translate the eosType id into a string

View file

@ -709,9 +709,7 @@ public:
* specification of the collision integrals. defaults to no. * specification of the collision integrals. defaults to no.
* @param log_level Defaults to zero, no logging * @param log_level Defaults to zero, no logging
*/ */
virtual void init(thermo_t* thermo, int mode=0, int log_level=0) { virtual void init(thermo_t* thermo, int mode=0, int log_level=0) {}
throw NotImplementedError("Transport::init");
}
//! Called by TransportFactory to set parameters. //! Called by TransportFactory to set parameters.
/*! /*!

View file

@ -26,7 +26,7 @@ namespace Cantera
* *
* @ingroup tranprops * @ingroup tranprops
*/ */
class TransportFactory : public FactoryBase class TransportFactory : public Factory<Transport>
{ {
public: public:
//! Return a pointer to a TransportFactory instance. //! Return a pointer to a TransportFactory instance.
@ -104,8 +104,7 @@ public:
* @param thermo ThermoPhase object * @param thermo ThermoPhase object
* @param log_level log level * @param log_level log level
*/ */
virtual Transport* virtual Transport* newTransport(thermo_t* thermo, int log_level=0);
newTransport(thermo_t* thermo, int log_level=0);
//! Initialize an existing transport manager for liquid phase //! Initialize an existing transport manager for liquid phase
/*! /*!
@ -242,6 +241,9 @@ private:
//! Mapping between between the string name for a //! Mapping between between the string name for a
//! liquid mixture transport property model and the integer name. //! liquid mixture transport property model and the integer name.
std::map<std::string, LiquidTranMixingModel> m_LTImodelMap; std::map<std::string, LiquidTranMixingModel> m_LTImodelMap;
//! Models included in this map are initialized in CK compatibility mode
std::map<std::string, bool> m_CK_mode;
}; };
//! Create a new transport manager instance. //! Create a new transport manager instance.

View file

@ -11,7 +11,7 @@
namespace Cantera namespace Cantera
{ {
class ReactorFactory : FactoryBase class ReactorFactory : public Factory<ReactorBase>
{ {
public: public:
static ReactorFactory* factory() { static ReactorFactory* factory() {
@ -38,7 +38,7 @@ public:
private: private:
static ReactorFactory* s_factory; static ReactorFactory* s_factory;
static std::mutex reactor_mutex; static std::mutex reactor_mutex;
ReactorFactory() {} ReactorFactory();
}; };
inline ReactorBase* newReactor(const std::string& model, inline ReactorBase* newReactor(const std::string& model,

View file

@ -12,22 +12,22 @@ namespace Cantera
FalloffFactory* FalloffFactory::s_factory = 0; FalloffFactory* FalloffFactory::s_factory = 0;
std::mutex FalloffFactory::falloff_mutex; 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* FalloffFactory::newFalloff(int type, const vector_fp& c)
{ {
Falloff* f; static const std::unordered_map<int, std::string> types {
switch (type) { {SIMPLE_FALLOFF, "Simple"},
case SIMPLE_FALLOFF: {TROE_FALLOFF, "Troe"},
f = new Falloff(); {SRI_FALLOFF, "SRI"}
break; };
case TROE_FALLOFF:
f = new Troe(); Falloff* f = create(types.at(type));
break;
case SRI_FALLOFF:
f = new SRI();
break;
default:
return 0;
}
f->init(c); f->init(c);
return f; return f;
} }

View file

@ -37,22 +37,17 @@ Kinetics* KineticsFactory::newKinetics(XML_Node& phaseData,
return k; 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) Kinetics* KineticsFactory::newKinetics(const string& model)
{ {
string lcmodel = lowercase(model); return create(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);
}
} }
} }

View file

@ -77,71 +77,39 @@ static int _itypes[] = {cIdealGas, cIncompressible,
cRedlichKwongMFTP, cRedlichKwongMFTP, cMaskellSolidSolnPhase cRedlichKwongMFTP, cRedlichKwongMFTP, cMaskellSolidSolnPhase
}; };
ThermoFactory::ThermoFactory()
{
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(); });
}
ThermoPhase* ThermoFactory::newThermoPhase(const std::string& model) ThermoPhase* ThermoFactory::newThermoPhase(const std::string& model)
{ {
int ieos=-1; return create(model);
for (int n = 0; n < ntypes; n++) {
if (model == _types[n]) {
ieos = _itypes[n];
break;
}
}
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);
}
} }
std::string eosTypeString(int ieos, int length) std::string eosTypeString(int ieos, int length)

View file

@ -183,6 +183,25 @@ static void getVPSSMgrTypes(std::vector<XML_Node*> & 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() void VPSSMgrFactory::deleteFactory()
{ {
std::unique_lock<std::mutex> lock(vpss_species_thermo_mutex); std::unique_lock<std::mutex> lock(vpss_species_thermo_mutex);
@ -230,7 +249,7 @@ VPSSMgr* VPSSMgrFactory::newVPSSMgr(VPStandardStateTP* vp_ptr,
} }
if (thermoNode.hasChild("variablePressureStandardStateManager")) { if (thermoNode.hasChild("variablePressureStandardStateManager")) {
const XML_Node& vpssNode = thermoNode.child("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 // Next, if we have specific directions, use them to get the VPSSSMgr object
// and return immediately // and return immediately
if (vpssManager != "") { if (vpssManager != "") {
VPSSMgr_enumType type = VPSSMgr_StringConversion(vpssManager); return create(vpssManager, vp_ptr, spth);
return newVPSSMgr(type, vp_ptr);
} }
// Handle special cases based on the VPStandardState types // Handle special cases based on the VPStandardState types
@ -292,27 +310,15 @@ VPSSMgr* VPSSMgrFactory::newVPSSMgr(VPStandardStateTP* vp_ptr,
VPSSMgr* VPSSMgrFactory::newVPSSMgr(VPSSMgr_enumType type, VPSSMgr* VPSSMgrFactory::newVPSSMgr(VPSSMgr_enumType type,
VPStandardStateTP* vp_ptr) VPStandardStateTP* vp_ptr)
{ {
static unordered_map<int, std::string> 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(); MultiSpeciesThermo& spthermoRef = vp_ptr->speciesThermo();
switch (type) { return create(types.at(type), vp_ptr, &spthermoRef);
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;
}
} }
// I don't think this is currently used // I don't think this is currently used

View file

@ -59,7 +59,7 @@ public:
* *
* @ingroup mgrpdssthermocalc * @ingroup mgrpdssthermocalc
*/ */
class VPSSMgrFactory : public FactoryBase class VPSSMgrFactory : public Factory<VPSSMgr, VPStandardStateTP*, MultiSpeciesThermo*>
{ {
public: public:
//! Static method to return an instance of this class //! Static method to return an instance of this class
@ -131,7 +131,7 @@ private:
//! Constructor. This is made private, so that only the static //! Constructor. This is made private, so that only the static
//! method factory() can instantiate the class. //! method factory() can instantiate the class.
VPSSMgrFactory() {} VPSSMgrFactory();
}; };
////////////////////// Convenience functions //////////////////// ////////////////////// Convenience functions ////////////////////

View file

@ -41,6 +41,16 @@ public:
TransportFactory::TransportFactory() 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["Mix"] = cMixtureAveraged;
m_models["Multi"] = cMulticomponent; m_models["Multi"] = cMulticomponent;
m_models["Solid"] = cSolidTransport; m_models["Solid"] = cSolidTransport;
@ -173,39 +183,12 @@ LiquidTranInteraction* TransportFactory::newLTI(const XML_Node& trNode,
Transport* TransportFactory::newTransport(const std::string& transportModel, Transport* TransportFactory::newTransport(const std::string& transportModel,
thermo_t* phase, int log_level, int ndim) thermo_t* phase, int log_level, int ndim)
{ {
if (transportModel == "") {
return new Transport;
}
vector_fp state; vector_fp state;
Transport* tr = 0, *gastr = 0; Transport* tr = 0, *gastr = 0;
DustyGasTransport* dtr = 0; DustyGasTransport* dtr = 0;
phase->saveState(state); phase->saveState(state);
switch (m_models[transportModel]) { 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: case cSolidTransport:
tr = new SolidTransport; tr = new SolidTransport;
initSolidTransport(tr, phase, log_level); initSolidTransport(tr, phase, log_level);
@ -229,7 +212,8 @@ Transport* TransportFactory::newTransport(const std::string& transportModel,
tr->setThermo(*phase); tr->setThermo(*phase);
break; break;
default: default:
throw CanteraError("newTransport","unknown transport model: " + transportModel); tr = create(transportModel);
tr->init(phase, m_CK_mode[transportModel], log_level);
} }
phase->restoreState(state); phase->restoreState(state);
return tr; return tr;

View file

@ -17,50 +17,39 @@ namespace Cantera
ReactorFactory* ReactorFactory::s_factory = 0; ReactorFactory* ReactorFactory::s_factory = 0;
std::mutex ReactorFactory::reactor_mutex; std::mutex ReactorFactory::reactor_mutex;
static int ntypes = 6; ReactorFactory::ReactorFactory()
static string _types[] = {"Reservoir", "Reactor", "ConstPressureReactor", {
"FlowReactor", "IdealGasReactor", reg("Reservoir", []() { return new Reservoir(); });
"IdealGasConstPressureReactor" reg("Reactor", []() { return new Reactor(); });
}; reg("ConstPressureReactor", []() { return new ConstPressureReactor(); });
reg("FlowReactor", []() { return new FlowReactor(); });
// these constants are defined in ReactorBase.h reg("IdealGasReactor", []() { return new IdealGasReactor(); });
static int _itypes[] = {ReservoirType, ReactorType, ConstPressureReactorType, reg("IdealGasConstPressureReactor", []() { return new IdealGasConstPressureReactor(); });
FlowReactorType, IdealGasReactorType, }
IdealGasConstPressureReactorType
};
ReactorBase* ReactorFactory::newReactor(const std::string& reactorType) ReactorBase* ReactorFactory::newReactor(const std::string& reactorType)
{ {
int ir=-1; return create(reactorType);
for (int n = 0; n < ntypes; n++) {
if (reactorType == _types[n]) {
ir = _itypes[n];
}
}
return newReactor(ir);
} }
ReactorBase* ReactorFactory::newReactor(int ir) ReactorBase* ReactorFactory::newReactor(int ir)
{ {
switch (ir) { static const unordered_map<int, string> types {
case ReservoirType: {ReservoirType, "Reservoir"},
return new Reservoir(); {ReactorType, "Reactor"},
case ReactorType: {ConstPressureReactorType, "ConstPressureReactor"},
return new Reactor(); {FlowReactorType, "FlowReactor"},
case FlowReactorType: {IdealGasReactorType, "IdealGasReactor"},
return new FlowReactor(); {IdealGasConstPressureReactorType, "IdealGasConstPressureReactor"}
case ConstPressureReactorType: };
return new ConstPressureReactor();
case IdealGasReactorType: try {
return new IdealGasReactor(); return create(types.at(ir));
case IdealGasConstPressureReactorType: } catch (out_of_range&) {
return new IdealGasConstPressureReactor();
default:
throw CanteraError("ReactorFactory::newReactor", throw CanteraError("ReactorFactory::newReactor",
"unknown reactor type!"); "unknown reactor type!");
} }
return 0;
} }
} }