From ad696108bb94e0b01415f123427d3165b528e43d Mon Sep 17 00:00:00 2001 From: Ian Bell Date: Fri, 15 Sep 2023 09:29:51 -0400 Subject: [PATCH] Add ability to add your own models to teqp without re-compiling the core Adds a lot of flexibility, maybe should be used for ALL models? --- include/teqp/cpp/teqpcpp.hpp | 11 +++++++ interface/CPP/teqp_impl_factory.cpp | 11 ++++++- src/test_runtime_model_inclusion.cpp | 47 ++++++++++++++++++++++++++++ 3 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 src/test_runtime_model_inclusion.cpp diff --git a/include/teqp/cpp/teqpcpp.hpp b/include/teqp/cpp/teqpcpp.hpp index d8f01811..90b50686 100644 --- a/include/teqp/cpp/teqpcpp.hpp +++ b/include/teqp/cpp/teqpcpp.hpp @@ -179,5 +179,16 @@ namespace teqp { /// Return the schema for the given model kind nlohmann::json get_model_schema(const std::string& kind); + + + using ModelPointerFactoryFunction = std::function(const nlohmann::json &j)>; + + /** + * \brief This function allows you to inject your own model factory function into the set of factory functions implemented in teqp. This allows you to add your own model at runtime. As an example of how to do this, see src/test_runtime_model_inclusion.cpp + * \param key The key used to define the model + * \param func The ModelPointerFactoryFunction factory function used to generate the wrapped model + */ + void add_model_pointer_factory_function(const std::string& key, ModelPointerFactoryFunction& func); + } } diff --git a/interface/CPP/teqp_impl_factory.cpp b/interface/CPP/teqp_impl_factory.cpp index 0e6ff5a7..6ca440cb 100644 --- a/interface/CPP/teqp_impl_factory.cpp +++ b/interface/CPP/teqp_impl_factory.cpp @@ -11,7 +11,7 @@ namespace teqp { std::unique_ptr make_SAFTVRMie(const nlohmann::json &j); - using makefunc = std::function(const nlohmann::json &j)>; + using makefunc = ModelPointerFactoryFunction; using namespace teqp::cppinterface::adapter; nlohmann::json get_model_schema(const std::string& kind) { return model_schema_library.at(kind); } @@ -72,5 +72,14 @@ namespace teqp { std::unique_ptr make_model(const nlohmann::json& j) { return build_model_ptr(j); } + + void add_model_pointer_factory_function(const std::string& key, ModelPointerFactoryFunction& func){ + if (pointer_factory.find(key) == pointer_factory.end()){ + pointer_factory[key] = func; + } + else{ + throw teqp::InvalidArgument("key is already present, overwriting is not currently allowed"); + } + } } } diff --git a/src/test_runtime_model_inclusion.cpp b/src/test_runtime_model_inclusion.cpp new file mode 100644 index 00000000..2b25ae87 --- /dev/null +++ b/src/test_runtime_model_inclusion.cpp @@ -0,0 +1,47 @@ +#include + +#include "teqp/cpp/teqpcpp.hpp" +#include "teqp/cpp/deriv_adapter.hpp" +#include "teqp/types.hpp" + +/// A (very) simple implementation of the van der Waals EOS, +class myvdWEOS1 { +private: + double a, b; +public: + myvdWEOS1(double a, double b) : a(a), b(b) {}; + + /// Accessor functions + double get_a() const{ return a; } + double get_b() const{ return b; } + + const double Ru = 1.380649e-23 * 6.02214076e23; ///< Exact value, given by k_B*N_A + + /// \brief Get the universal gas constant + /// \note Here the real universal gas constant, with no composition dependence + template + auto R(const VecType& /*molefrac*/) const { return Ru; } + + /// The evaluation of \f$ \alpha^{\rm r}=a/(RT) \f$ + /// \param T The temperature + /// \param rhotot The molar density + /// \param molefrac The mole fractions of each component + template + auto alphar(const TType &T, const RhoType& rhotot, const VecType &molefrac) const { + return teqp::forceeval(-log(1.0 - b * rhotot) - (a / (R(molefrac) * T)) * rhotot); + } +}; + +TEST_CASE("Check adding a model at runtime"){ + using namespace teqp::cppinterface; + using namespace teqp::cppinterface::adapter; + + auto j = R"protect( + {"kind": "myvdW", "model": {"a":1.2, "b": 3.4}} + )protect"_json; + + ModelPointerFactoryFunction func = [](const nlohmann::json& j){ return make_owned(myvdWEOS1(j.at("a"), j.at("b"))); }; + add_model_pointer_factory_function("myvdW", func); + + auto ptr = make_model(j); +}