teqp 0.21.0
Loading...
Searching...
No Matches
pure_param_optimization.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <tuple>
4#include <variant>
5
6#include "nlohmann/json.hpp"
8#include "teqp/exceptions.hpp"
10
11#include <boost/asio/thread_pool.hpp>
12#include <boost/asio/post.hpp>
13
15
18 auto check_fields() const{}
19 template<typename Model>
20 auto calculate_contribution(const Model& model) const{
21 auto rhoLrhoV = model->pure_VLE_T(T, rhoL_guess, rhoV_guess, 10);
22 return std::abs(rhoLrhoV[0]-rhoL_exp)*weight;
23 }
24};
25
26#define stdstringify(s) std::string(#s)
27
28#define SatRhoLPPoint_optionalfields X(T) X(p_exp) X(rhoL_exp) X(rhoL_guess) X(rhoV_guess)
30 #define X(field) std::optional<double> field;
32 #undef X
33 double weight_rho=1.0, weight_p=1.0, R=8.31446261815324;
34 Eigen::ArrayXd z = (Eigen::ArrayXd(1) << 1.0).finished();
35
36 auto check_fields() const{
37 #define X(field) if (!field){ throw teqp::InvalidArgument("A field [" + stdstringify(field) + "] has not been initialized"); }
39 #undef X
40 }
41
42 template<typename Model>
43 auto calculate_contribution(const Model& model) const{
44 auto rhoLrhoV = model->pure_VLE_T(T.value(), rhoL_guess.value(), rhoV_guess.value(), 10);
45 auto rhoL = rhoLrhoV[0];
46 auto p = rhoL*R*T.value()*(1+model->get_Ar01(T.value(), rhoL, z));
47// std::cout << p << "," << p_exp << "," << (p_exp-p)/p_exp << std::endl;
48 return std::abs(rhoL-rhoL_exp.value())/rhoL_exp.value()*weight_rho + std::abs(p-p_exp.value())/p_exp.value()*weight_p;
49 }
50};
51
52#define SatRhoLPWPoint_optionalfields X(T) X(p_exp) X(rhoL_exp) X(w_exp) X(rhoL_guess) X(rhoV_guess) X(Ao20) X(M) X(R)
54
55 #define X(field) std::optional<double> field;
57 #undef X
58 double weight_rho=1.0, weight_p=1.0, weight_w=1.0;
59 Eigen::ArrayXd z = (Eigen::ArrayXd(1) << 1.0).finished();
60
61 auto check_fields() const{
62 #define X(field) if (!field){ throw teqp::InvalidArgument("A field [" + stdstringify(field) + "] has not been initialized"); }
64 #undef X
65 }
66
67 template<typename Model>
68 auto calculate_contribution(const Model& model) const{
69
70 auto rhoLrhoV = model->pure_VLE_T(T.value(), rhoL_guess.value(), rhoV_guess.value(), 10);
71
72 // First part, density
73 auto rhoL = rhoLrhoV[0];
74
75 auto Ar0n = model->get_Ar02n(T.value(), rhoL, z);
76 double Ar01 = Ar0n[1], Ar02 = Ar0n[2];
77 auto Ar11 = model->get_Ar11(T.value(), rhoL, z);
78 auto Ar20 = model->get_Ar20(T.value(), rhoL, z);
79
80 // Second part, presure
81 auto p = rhoL*R.value()*T.value()*(1+Ar01);
82
83 // Third part, speed of sound
84 //
85 // M*w^2/(R*T) where w is the speed of sound
86 // from the definition w = sqrt(dp/drho|s)
87 double Mw2RT = 1 + 2*Ar01 + Ar02 - POW2(1.0 + Ar01 - Ar11)/(Ao20.value() + Ar20);
88 double w = sqrt(Mw2RT*R.value()*T.value()/M.value());
89
90// std::cout << p << "," << p_exp << "," << (p_exp-p)/p_exp << std::endl;
91 double cost_rhoL = std::abs(rhoL-rhoL_exp.value())/rhoL_exp.value()*weight_rho;
92 double cost_p = std::abs(p-p_exp.value())/p_exp.value()*weight_p;
93 double cost_w = std::abs(w-w_exp.value())/w_exp.value()*weight_w;
94 return ((weight_rho != 0) ? cost_rhoL : 0) + ((weight_p != 0) ? cost_p : 0) + ((weight_w != 0) ? cost_w : 0);
95 }
96};
97
98#define SOSPoint_fields X(T) X(p_exp) X(rho_guess) X(w_exp) X(Ao20) X(M) X(R)
99struct SOSPoint{
100
101 #define X(field) std::optional<double> field;
103 #undef X
104
105 double weight_w=1.0;
106 Eigen::ArrayXd z = (Eigen::ArrayXd(1) << 1.0).finished();
107
108 auto check_fields() const{
109 #define X(field) if (!field){ throw teqp::InvalidArgument("A field [" + stdstringify(field) + "] has not been initialized"); }
111 #undef X
112 }
113
114 template<typename Model>
115 auto calculate_contribution(const Model& model) const{
116
117 double rho = rho_guess.value();
118 double R_ = R.value();
119 double T_K_ = T.value();
120
121 // First part, iterate for density
122 // ...
123 for (auto step = 0; step < 10; ++step){
124 auto Ar0n = model->get_Ar02n(T_K_, rho, z);
125 double Ar01 = Ar0n[1], Ar02 = Ar0n[2];
126 double pEOS = rho*R_*T_K_*(1+Ar01);
127 double dpdrho = R_*T_K_*(1 + 2*Ar0n[1] + Ar0n[2]);
128 double res = (pEOS-p_exp.value())/p_exp.value();
129 double dresdrho = dpdrho/p_exp.value();
130 double change = -res/dresdrho;
131 if (std::abs(change/rho-1) < 1e-10 || abs(res) < 1e-12){
132 break;
133 }
134 rho += change;
135 }
136
137 // Second part, speed of sound
138 //
139 auto Ar0n = model->get_Ar02n(T_K_, rho, z);
140 double Ar01 = Ar0n[1], Ar02 = Ar0n[2];
141 auto Ar11 = model->get_Ar11(T_K_, rho, z);
142 auto Ar20 = model->get_Ar20(T_K_, rho, z);
143
144 // M*w^2/(R*T) where w is the speed of sound
145 // from the definition w = sqrt(dp/drho|s)
146 double Mw2RT = 1.0 + 2.0*Ar01 + Ar02 - POW2(1.0 + Ar01 - Ar11)/(Ao20.value() + Ar20);
147 double w = sqrt(Mw2RT*R_*T_K_/M.value());
148 double cost_w = std::abs(w-w_exp.value())/w_exp.value()*weight_w;
149 return cost_w;
150 }
151};
152
153using PureOptimizationContribution = std::variant<SatRhoLPoint, SatRhoLPPoint, SatRhoLPWPoint, SOSPoint>;
154
156private:
157 auto make_pointers(const std::vector<std::variant<std::string, std::vector<std::string>>>& pointerstrs){
158 std::vector<std::vector<nlohmann::json::json_pointer>> pointers_;
159 for (auto & pointer: pointerstrs){
160 if (std::holds_alternative<std::string>(pointer)){
161 const std::string& s= std::get<std::string>(pointer);
162 pointers_.emplace_back(1, nlohmann::json::json_pointer(s));
163 }
164 else{
165 std::vector<nlohmann::json::json_pointer> buffer;
166 for (const auto& s : std::get<std::vector<std::string>>(pointer)){
167 buffer.emplace_back(s);
168 }
169 pointers_.push_back(buffer);
170 }
171 }
172 return pointers_;
173 }
174public:
175 const nlohmann::json jbase;
176 std::vector<std::vector<nlohmann::json::json_pointer>> pointers;
177 std::vector<PureOptimizationContribution> contributions;
178
179 PureParameterOptimizer(const nlohmann::json jbase, const std::vector<std::variant<std::string, std::vector<std::string>>>& pointerstrs) : jbase(jbase), pointers(make_pointers(pointerstrs)){}
180
182 std::visit([](const auto&c){c.check_fields();}, cont);
183 contributions.push_back(cont);
184 }
185
186 auto prepare_helper_models(const auto& model) const {
187 return std::vector<double>{1, 3};
188 }
189
190 template<typename T>
191 nlohmann::json build_JSON(const T& x) const{
192
193 if (x.size() != pointers.size()){
194 throw teqp::InvalidArgument("sizes don't match");
195 };
196 nlohmann::json j = jbase;
197 for (auto i = 0; i < x.size(); ++i){
198 for (const auto& ptr : pointers[i]){
199 j.at(ptr) = x[i];
200 }
201 }
202 return j;
203 }
204
205 template<typename T>
206 auto prepare(const T& x) const {
207 auto j = build_JSON(x);
208 auto model = teqp::cppinterface::make_model(j);
209 auto helpers = prepare_helper_models(model);
210 return std::make_tuple(std::move(model), helpers);
211 }
212
213 template<typename T>
214 auto cost_function(const T& x) const{
215 const auto [_model, _helpers] = prepare(x);
216 const auto& model = _model;
217 const auto& helpers = _helpers;
218 double cost = 0.0;
219 for (const auto& contrib : contributions){
220 cost += std::visit([&model](const auto& c){ return c.calculate_contribution(model); }, contrib);
221 }
222 if (!std::isfinite(cost)){
223 return 1e30;
224 }
225 return cost;
226 }
227
228 template<typename T>
229 auto cost_function_threaded(const T& x, std::size_t Nthreads) {
230 boost::asio::thread_pool pool{Nthreads}; // Nthreads in the pool
231 const auto [_model, _helpers] = prepare(x);
232 const auto& model = _model;
233 const auto& helpers = _helpers;
234 std::valarray<double> buffer(contributions.size());
235 std::size_t i = 0;
236 for (const auto& contrib : contributions){
237 auto& dest = buffer[i];
238 auto payload = [&model, &dest, contrib] (){
239 dest = std::visit([&model](const auto& c){ return c.calculate_contribution(model); }, contrib);
240 if (!std::isfinite(dest)){ dest = 1e30; }
241 };
242 boost::asio::post(pool, payload);
243 i++;
244 }
245 pool.join();
246 double summer = 0.0;
247 for (auto i = 0; i < contributions.size(); ++i){
248// std::cout << buffer[i] << std::endl;
249 summer += buffer[i];
250 }
251// std::cout << summer << std::endl;
252 return summer;
253 }
254
255};
256
257}
PureParameterOptimizer(const nlohmann::json jbase, const std::vector< std::variant< std::string, std::vector< std::string > > > &pointerstrs)
std::vector< std::vector< nlohmann::json::json_pointer > > pointers
std::variant< SatRhoLPoint, SatRhoLPPoint, SatRhoLPWPoint, SOSPoint > PureOptimizationContribution
std::unique_ptr< AbstractModel > make_model(const nlohmann::json &, bool validate=true)
auto POW2(const A &x)
#define SatRhoLPWPoint_optionalfields
#define SOSPoint_fields
#define SatRhoLPPoint_optionalfields