Skip to content

Commit

Permalink
Add ability to add your own models to teqp without re-compiling the core
Browse files Browse the repository at this point in the history
Adds a lot of flexibility, maybe should be used for ALL models?
  • Loading branch information
ianhbell committed Sep 15, 2023
1 parent 326242e commit ad69610
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 1 deletion.
11 changes: 11 additions & 0 deletions include/teqp/cpp/teqpcpp.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<std::unique_ptr<teqp::cppinterface::AbstractModel>(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);

}
}
11 changes: 10 additions & 1 deletion interface/CPP/teqp_impl_factory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ namespace teqp {

std::unique_ptr<teqp::cppinterface::AbstractModel> make_SAFTVRMie(const nlohmann::json &j);

using makefunc = std::function<std::unique_ptr<teqp::cppinterface::AbstractModel>(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); }
Expand Down Expand Up @@ -72,5 +72,14 @@ namespace teqp {
std::unique_ptr<AbstractModel> 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");
}
}
}
}
47 changes: 47 additions & 0 deletions src/test_runtime_model_inclusion.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
#include <catch2/catch_test_macros.hpp>

#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<class VecType>
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<typename TType, typename RhoType, typename VecType>
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);
}

0 comments on commit ad69610

Please sign in to comment.