From 043fc17aa28447a1968285028e0c0db8fe949ec6 Mon Sep 17 00:00:00 2001 From: Ian Bell <ian.bell@nist.gov> Date: Mon, 10 May 2021 15:19:37 -0400 Subject: [PATCH] Add a model container and a testing file --- include/teqp/containers.hpp | 48 +++++++++++++++++++ src/teqp_profile.cpp | 96 +++++++++++++++++++++++++++++++++++++ src/test_variant.cpp | 80 +++++++++++++++++++++++++++++++ 3 files changed, 224 insertions(+) create mode 100644 include/teqp/containers.hpp create mode 100644 src/teqp_profile.cpp create mode 100644 src/test_variant.cpp diff --git a/include/teqp/containers.hpp b/include/teqp/containers.hpp new file mode 100644 index 0000000..2f750fb --- /dev/null +++ b/include/teqp/containers.hpp @@ -0,0 +1,48 @@ +#pragma once + +//template <typename T> +//concept has_meta = requires(T const& m) { +// { m.get_meta() }; +//}; + +template<typename... Args> +class ModelContainer { +public: + using mid = std::size_t; + using varModels = std::variant<Args...>; +private: + mid last_id = 0; + std::map<mid, varModels> modcoll; +public: + template <typename T> const auto& get_ref(mid id) { return std::get<T>(get_model(id)); } + + auto size() const { return modcoll.size(); } + auto new_id() { + last_id++; + return last_id; + } + template<typename Instance> + auto add_model(Instance&& instance) { + auto uid = new_id(); + modcoll.emplace(uid, std::move(instance)); + return uid; + } + + const varModels& get_model(mid id) const { + return modcoll.at(id); + } + + template <typename Function> + auto caller(const mid& mid, const Function &f) const { + return std::visit([&](auto& model) { return f(model); }, get_model(mid)); + } + + //nlohmann::json get_meta(const mid& mid) const { + // const auto& modvar = get_model(mid); + // nlohmann::json result; + // std::visit([&](auto&& model) { + // if constexpr (has_meta<decltype(model)>) { result = model.get_meta(); } + // }, modvar); + // return result; + //} +}; \ No newline at end of file diff --git a/src/teqp_profile.cpp b/src/teqp_profile.cpp new file mode 100644 index 0000000..9a0af08 --- /dev/null +++ b/src/teqp_profile.cpp @@ -0,0 +1,96 @@ +#include <vector> +#include <iostream> +#include <complex> +#include <variant> +#include <chrono> + +#include "teqp/types.hpp" +#include "nlohmann/json.hpp" +#include "teqp/models/eos.hpp" +//#include "teqp/models/CPA.hpp" +#include "teqp/models/multifluid.hpp" +#include "teqp/models/pcsaft.hpp" +#include "teqp/containers.hpp" +#include <Eigen/Dense> +#include "teqp/derivs.hpp" + +class Timer { +private: + int N; + decltype(std::chrono::steady_clock::now()) tic; +public: + Timer(int N) : N(N), tic(std::chrono::steady_clock::now()) {} + ~Timer() { + auto elap = std::chrono::duration<double>(std::chrono::steady_clock::now() - tic).count(); + std::cout << elap / N * 1e6 << " us/call" << std::endl; + } +}; + +template <typename ModelContainer, typename T1, typename T2, typename T3> +auto get_f(const ModelContainer& modcon, const T1& x1, const T2& x2, const T3& x3) { + // Call the function with T, rho, molefrac arguments + return std::visit([&](auto&& model) { return model.alphar(x1, x2, x3); }, modcon); +} + +int main() { + // Here, all models that can be stored in this container are defined. Types may + // be obtained from factory functions without explicit definition + using MFType = decltype(build_multifluid_model(std::vector<std::string>{"", ""}, "", "")); + ModelContainer<vdWEOS1, vdWEOS<double>, MFType, PCSAFTMixture> mc; + std::vector<int> indices; + + auto adder = [&](auto&&m) { indices.push_back(mc.add_model(m)); }; + + adder(vdWEOS1(1, 2)); + adder(vdWEOS<double>({ 150.687 }, { 4863000.0 })); + adder(PCSAFTMixture({ "Methane" })); + adder(build_multifluid_model({ "Methane" }, "../mycp", "../mycp/dev/mixtures/mixture_binary_pairs.json")); + + double x1 = 3.0; + double x2 = 2.0; + auto c = (Eigen::ArrayXd(1) << 1.0).finished(); + int N = 100000; + + auto f_alphar = [&x1, &x2, &c](auto& model) { return model.alphar(x1, x2, c); }; + auto alphar = mc.caller(1, f_alphar); + //auto meta = mc.caller(1, [&x1, &x2, &c](auto& model) { return model.get_meta(); }); + + auto m = mc.get_ref<MFType>(4); + m.alphar(x2, x2, c); + { + Timer t(N); + for (auto j = 0; j < N; ++j) { + auto v = m.alphar(x1, x2, c); + //std::cout << v << std::endl; + } + } + for (auto counter = 0; counter < 10; ++counter){ + Timer t(N); + for (auto j = 0; j < N; ++j) { + x1 += j * 1e-10; + //auto f_Ar01 = [&x1, &x2, &c](auto& model) { using tdx = TDXDerivatives<decltype(model), decltype(x1), decltype(c)>; return tdx::get_Ar02(model, x1, x2, c); }; + auto v = mc.caller(4, [&x1, &x2, &c](auto& model) { using tdx = TDXDerivatives<decltype(model), decltype(x1), decltype(c)>; return tdx::get_Ar00(model, x1, x2, c); }); + //std::cout << v << std::endl; + } + } + + ////std::complex<double> x2(3.0, 1.0); + //std::cout << "----" << std::endl; + //for (auto i : indices) { + // const auto& m = mc.get_model(i); + // Timer t(N); + // for (auto j = 0; j < N; ++j) { + // auto v = get_f(m, x1, x2, c); + // //std::cout << v << std::endl; + // } + //} + //std::cout << "----" << std::endl; + //for (auto i : indices) { + // Timer t(N); + // for (auto j = 0; j < N; ++j) { + // auto v = mc.caller(i, f_alphar); + // //std::cout << v << std::endl; + // } + // auto f_alphar = [&x1, &x2, &c](auto& model) { return model(x1, x2, c); }; + //} +} \ No newline at end of file diff --git a/src/test_variant.cpp b/src/test_variant.cpp new file mode 100644 index 0000000..bb55749 --- /dev/null +++ b/src/test_variant.cpp @@ -0,0 +1,80 @@ +#include <vector> +#include <iostream> +#include <complex> +#include <variant> +#include <chrono> +#include <map> +#include <valarray> + +#include "teqp/types.hpp" +#include "nlohmann/json.hpp" +#include "teqp/models/eos.hpp" +//#include "teqp/models/CPA.hpp" +#include "teqp/models/multifluid.hpp" +#include "teqp/models/pcsaft.hpp" +#include "teqp/containers.hpp" +#include <Eigen/Dense> + +class Timer { +private: + int N; + decltype(std::chrono::steady_clock::now()) tic; +public: + Timer(int N) : N(N), tic(std::chrono::steady_clock::now()){} + ~Timer() { + auto elap = std::chrono::duration<double>(std::chrono::steady_clock::now()-tic).count(); + std::cout << elap/N*1e6 << " us/call" << std::endl; + } +}; + +template <typename ModelContainer, typename T1, typename T2, typename T3> +auto get_f(const ModelContainer &modcon, const T1& x1, const T2& x2, const T3& x3){ + // The output type is the type promotion of T, rho, and molefrac + std::common_type_t<T1, T2, decltype(x3[0])> result = -1; + // Call the function with T, rho, molefrac arguments + std::visit([&](auto&& model) { result = model.alphar(x1, x2, x3); }, modcon); + return result; +} + +int main(){ + // Here, all models that can be stored in this container are defined. Types may + // be obtained from factory functions without explicit definition + using MFType = decltype(build_multifluid_model(std::vector<std::string>{"", ""}, "", "")); + ModelContainer<MFType, vdWEOS<double>, vdWEOS1> mc; + nlohmann::json vdWargs = { { "a",3 }, { "b", 4 } }; + std::string vdWs = vdWargs.dump(); + for (auto i = 0; i < 10; ++i) { + mc.add_model(vdWEOS1(1, 2)); + } + const auto& v = mc.get_ref<vdWEOS1>(1); + + auto c = (Eigen::ArrayXd(2) << 3.0, 3.0).finished(); + int N = 1000; + volatile double x1 = 3.0; + std::complex<double> x2(3.0, 1.0); + vdWEOS1 b1(3, 4); + for (auto i = 0; i < mc.size(); ++i) { + Timer t(N); + for (auto j = 0; j < N; ++j) { + volatile auto v = b1.alphar(x1, x2, c); + //std::cout << v << std::endl; + } + } + std::cout << "----" << std::endl; + for (auto i = 0; i < mc.size(); ++i) { + const auto& m = mc.get_model(1); + Timer t(N); + for (auto j = 0; j < N; ++j) { + auto v = get_f(m, x1, x2, c); + //std::cout << v << std::endl; + } + } + std::cout << "----" << std::endl; + for (auto i = 1; i <= mc.size(); ++i) { + Timer t(N); + for (auto j = 0; j < N; ++j) { + auto v = mc.get_alphar(i, x1, x2, c); + //std::cout << v << std::endl; + } + } +} \ No newline at end of file -- GitLab