diff --git a/include/AbstractState.h b/include/AbstractState.h index 2f4da7be..f7de2b2d 100644 --- a/include/AbstractState.h +++ b/include/AbstractState.h @@ -12,6 +12,7 @@ #include "Exceptions.h" #include "DataStructures.h" #include "PhaseEnvelope.h" +#include "crossplatform_shared_ptr.h" #include @@ -1132,6 +1133,23 @@ public: return _d4alphar_dTau4; }; }; + +/** An abstract AbstractState generator class + * + * This class should be derived and statically initialized in a C++ file. In the initializer, + * the register_backend function should be called. This will register the backend family, and + * when this generator is looked up in the map, the get_AbstractState function will be used + * to return an initialized instance + */ +class AbstractStateGenerator{ +public: + virtual AbstractState * get_AbstractState(const std::vector &fluid_names) = 0; +}; + +/** Register a backend in the backend library (statically defined in AbstractState.cpp and not + * publically accessible) + */ +void register_backend(const backend_families &bf, shared_ptr gen); } /* namespace CoolProp */ #endif /* ABSTRACTSTATE_H_ */ diff --git a/src/AbstractState.cpp b/src/AbstractState.cpp index c0d650fe..41dc775a 100644 --- a/src/AbstractState.cpp +++ b/src/AbstractState.cpp @@ -13,13 +13,6 @@ #include "math.h" #include "AbstractState.h" #include "DataStructures.h" -#include "Backends/REFPROP/REFPROPBackend.h" -#include "Backends/Helmholtz/HelmholtzEOSBackend.h" -#include "Backends/Incompressible/IncompressibleBackend.h" -#include "Backends/Helmholtz/Fluids/FluidLibrary.h" -#include "Backends/IF97/IF97Backend.h" -#include "Backends/Cubics/CubicBackend.h" -#include "Backends/Cubics/VTPRBackend.h" #if !defined(NO_TABULAR_BACKENDS) #include "Backends/Tabular/TTSEBackend.h" @@ -28,6 +21,30 @@ namespace CoolProp { +/// This tiny class holds pointers to generators for the backends and can be used to look up +/// generators at runtime. This class should be populated through the use of static initialized +/// classes that were passed to register_backend +class BackendLibrary{ +private: + std::map > backends; +public: + void add_backend(const backend_families &bg, const shared_ptr &asg){ + backends[bg] = asg; + }; + void get_generator_iterators(const backend_families &bg, + std::map >::const_iterator &generator, + std::map >::const_iterator &end){ + generator = backends.find(bg); + end = backends.end(); + }; +}; +static BackendLibrary backend_library; + +/// Register the backend (should probably be done with static initialization) +void register_backend(const backend_families &bf, shared_ptr gen){ + backend_library.add_backend(bf, gen); +}; + AbstractState * AbstractState::factory(const std::string &backend, const std::vector &fluid_names) { if (get_debug_level() > 0){ @@ -37,32 +54,13 @@ AbstractState * AbstractState::factory(const std::string &backend, const std::ve backend_families f1; std::string f2; extract_backend_families_string(backend, f1, f2); - if (f1==HEOS_BACKEND_FAMILY) - { - if (fluid_names.size() == 1){ - return new HelmholtzEOSBackend(fluid_names[0]); - } - else{ - return new HelmholtzEOSMixtureBackend(fluid_names); - } - } - else if (f1==REFPROP_BACKEND_FAMILY) - { - if (fluid_names.size() == 1){ - return new REFPROPBackend(fluid_names[0]); - } - else{ - return new REFPROPMixtureBackend(fluid_names); - } - } - else if (f1==INCOMP_BACKEND_FAMILY) - { - if (fluid_names.size() != 1){throw ValueError(format("For INCOMP backend, name vector must be one element long"));} - return new IncompressibleBackend(fluid_names[0]); - } - else if (f1==IF97_BACKEND_FAMILY) - { - return new IF97Backend(); + + std::map >::const_iterator gen, end; + backend_library.get_generator_iterators(f1, gen, end); + + if (gen != end){ + // One of the registered backends was able to match the given backend family + return gen->second->get_AbstractState(fluid_names); } #if !defined(NO_TABULAR_BACKENDS) else if (f1==TTSE_BACKEND_FAMILY) @@ -78,22 +76,6 @@ AbstractState * AbstractState::factory(const std::string &backend, const std::ve return new BicubicBackend(AS); } #endif - else if (f1==TREND_BACKEND_FAMILY) - { - throw ValueError("TREND backend not yet implemented"); - } - else if (f1 == SRK_BACKEND_FAMILY) - { - return new SRKBackend(fluid_names, get_config_double(R_U_CODATA)); - } - else if (f1==PR_BACKEND_FAMILY) - { - return new PengRobinsonBackend(fluid_names, get_config_double(R_U_CODATA)); - } - else if (f1==VTPR_BACKEND_FAMILY) - { - return new VTPRBackend(fluid_names, get_config_double(R_U_CODATA)); - } else if (!backend.compare("?") || backend.empty()) { std::size_t idel = fluid_names[0].find("::"); diff --git a/src/Backends/Cubics/CubicBackend.cpp b/src/Backends/Cubics/CubicBackend.cpp index ad65a8f3..a627a295 100644 --- a/src/Backends/Cubics/CubicBackend.cpp +++ b/src/Backends/Cubics/CubicBackend.cpp @@ -1,7 +1,27 @@ #include "CubicBackend.h" #include "Solvers.h" +#include "Configuration.h" #include "Backends/Helmholtz/VLERoutines.h" +static class SRKGenerator : public CoolProp::AbstractStateGenerator{ +public: + SRKGenerator(){ + register_backend(CoolProp::SRK_BACKEND_FAMILY, shared_ptr(this)); + } + CoolProp::AbstractState * get_AbstractState(const std::vector &fluid_names){ + return new CoolProp::SRKBackend(fluid_names, CoolProp::get_config_double(R_U_CODATA)); + }; +} srk_gen; +static class PRGenerator : public CoolProp::AbstractStateGenerator{ +public: + PRGenerator(){ + register_backend(CoolProp::PR_BACKEND_FAMILY, shared_ptr(this)); + } + CoolProp::AbstractState * get_AbstractState(const std::vector &fluid_names){ + return new CoolProp::PengRobinsonBackend(fluid_names, CoolProp::get_config_double(R_U_CODATA)); + }; +} pr_gen; + void CoolProp::AbstractCubicBackend::setup(bool generate_SatL_and_SatV){ N = cubic->get_Tc().size(); diff --git a/src/Backends/Cubics/VTPRBackend.cpp b/src/Backends/Cubics/VTPRBackend.cpp index 7b6df22a..65a07d0d 100644 --- a/src/Backends/Cubics/VTPRBackend.cpp +++ b/src/Backends/Cubics/VTPRBackend.cpp @@ -11,6 +11,17 @@ static UNIFACLibrary::UNIFACParameterLibrary lib; +static class VTPRGenerator : public CoolProp::AbstractStateGenerator{ +public: + VTPRGenerator(){ + register_backend(CoolProp::VTPR_BACKEND_FAMILY, shared_ptr(this)); + } + CoolProp::AbstractState * get_AbstractState(const std::vector &fluid_names){ + return new CoolProp::VTPRBackend(fluid_names, CoolProp::get_config_double(R_U_CODATA)); + }; +} vtpr_gen; // This static initialization will cause the generator to register + + void CoolProp::VTPRBackend::setup(const std::vector &names, bool generate_SatL_and_SatV){ R = get_config_double(R_U_CODATA); diff --git a/src/Backends/Helmholtz/HelmholtzEOSMixtureBackend.cpp b/src/Backends/Helmholtz/HelmholtzEOSMixtureBackend.cpp index 67a073a6..a00a316d 100644 --- a/src/Backends/Helmholtz/HelmholtzEOSMixtureBackend.cpp +++ b/src/Backends/Helmholtz/HelmholtzEOSMixtureBackend.cpp @@ -40,6 +40,22 @@ static int deriv_counter = 0; namespace CoolProp { + +// This static initialization will cause the generator to register +static class HEOSGenerator : public AbstractStateGenerator{ +public: + HEOSGenerator(){ + register_backend(HEOS_BACKEND_FAMILY, shared_ptr(this)); + } + AbstractState * get_AbstractState(const std::vector &fluid_names){ + if (fluid_names.size() == 1){ + return new HelmholtzEOSBackend(fluid_names[0]); + } + else{ + return new HelmholtzEOSMixtureBackend(fluid_names); + } + }; +} heos_gen; HelmholtzEOSMixtureBackend::HelmholtzEOSMixtureBackend(){ imposed_phase_index = iphase_not_imposed; diff --git a/src/Backends/IF97/IF97Backend.cpp b/src/Backends/IF97/IF97Backend.cpp index a79da0e2..a9e7f84c 100644 --- a/src/Backends/IF97/IF97Backend.cpp +++ b/src/Backends/IF97/IF97Backend.cpp @@ -1 +1,15 @@ -#include "IF97Backend.h" \ No newline at end of file + + +#include "IF97Backend.h" +#include "AbstractState.h" +#include "DataStructures.h" + +static class IF97BackendGenerator : public CoolProp::AbstractStateGenerator{ +public: + IF97BackendGenerator(){ + register_backend(CoolProp::IF97_BACKEND_FAMILY, shared_ptr(this)); + } + CoolProp::AbstractState * get_AbstractState(const std::vector &fluid_names){ + return new CoolProp::IF97Backend(); + }; +} if97_gen; // This static initialization will cause the generator to register \ No newline at end of file diff --git a/src/Backends/Incompressible/IncompressibleBackend.cpp b/src/Backends/Incompressible/IncompressibleBackend.cpp index d63bbb68..4531a596 100644 --- a/src/Backends/Incompressible/IncompressibleBackend.cpp +++ b/src/Backends/Incompressible/IncompressibleBackend.cpp @@ -21,6 +21,17 @@ #include "MatrixMath.h" namespace CoolProp { + +static class IncompressibleBackendGenerator : public AbstractStateGenerator{ +public: + IncompressibleBackendGenerator(){ + register_backend(INCOMP_BACKEND_FAMILY, shared_ptr(this)); + } + AbstractState * get_AbstractState(const std::vector &fluid_names){ + if (fluid_names.size() != 1){throw ValueError(format("For INCOMP backend, name vector must be one element long"));} + return new IncompressibleBackend(fluid_names[0]); + }; +} incomp_gen; // This static initialization will cause the generator to register IncompressibleBackend::IncompressibleBackend() { throw NotImplementedError("Empty constructor is not implemented for incompressible fluids"); diff --git a/src/Backends/REFPROP/REFPROPMixtureBackend.cpp b/src/Backends/REFPROP/REFPROPMixtureBackend.cpp index 323d99a2..ee70fe51 100644 --- a/src/Backends/REFPROP/REFPROPMixtureBackend.cpp +++ b/src/Backends/REFPROP/REFPROPMixtureBackend.cpp @@ -27,11 +27,14 @@ surface tension N/m #include "CoolPropTools.h" #include "REFPROPMixtureBackend.h" +#include "REFPROPBackend.h" #include "Exceptions.h" #include "Configuration.h" #include "CoolProp.h" #include "Solvers.h" #include "IdealCurves.h" +#include "DataStructures.h" +#include "AbstractState.h" #include #include @@ -127,6 +130,23 @@ std::string get_REFPROP_HMX_BNC_path() } namespace CoolProp { + +// This static initialization will cause the generator to register +static class REFPROPGenerator : public AbstractStateGenerator{ +public: + REFPROPGenerator(){ + register_backend(REFPROP_BACKEND_FAMILY, shared_ptr(this)); + } + AbstractState * get_AbstractState(const std::vector &fluid_names){ + bool REFPROP_is_supported = REFPROPMixtureBackend::REFPROP_supported (); + if (fluid_names.size() == 1){ + return new REFPROPBackend(fluid_names[0]); + } + else{ + return new REFPROPMixtureBackend(fluid_names); + } + }; +} refprop_gen; void REFPROPMixtureBackend::construct(const std::vector& fluid_names) {