9#include <boost/multiprecision/cpp_bin_float.hpp>
25 const Eigen::Array2d&
x;
26 const Eigen::Array2d&
dx;
27 const Eigen::Array2d&
r;
40 virtual std::string
desc() = 0;
51 return (data.
r.abs().maxCoeff() < threshold) ? s::success : s::keep_going;
53 std::string
desc()
override{
54 return "MaxAbsErrorCondition";
71 double val = std::abs(data.
dx(idx)/data.
x(idx));
72 minval = std::min(val, minval);
74 return (minval < threshold) ? s::success : s::keep_going;
76 std::string
desc()
override{
77 return "MinRelStepsizeCondition";
88 bool allfinite =
true;
90 if (!std::isfinite(data.
x(idx)) || !std::isfinite(data.
dx(idx))){
91 allfinite =
false;
break;
94 return (!allfinite) ? s::fatal : s::keep_going;
96 std::string
desc()
override{
97 return "NanXDXErrorCondition";
105 bool allpositive =
true;
107 if (data.
x(idx) < 0){
108 allpositive =
false;
break;
111 return (!allpositive) ? s::fatal : s::keep_going;
114 return "NegativeXErrorCondition";
120 const std::size_t Nmax;
125 return (data.
N >= Nmax) ? s::fatal : s::keep_going;
128 return "StepCountErrorCondition";
144 auto get_R(
const std::vector<double>& z)
const{
145 const auto zz = Eigen::Map<const Eigen::ArrayXd>(&z[0], z.size());
154 Eigen::Array33d
get_deriv_mat2(
double T,
double rho,
const std::vector<double>& z)
const{
155 const auto zz = Eigen::Map<const Eigen::ArrayXd>(&z[0], z.size());
163 return std::make_tuple(A00A01[0], A10, A00A01[1]);
176 template<
typename Array>
177 auto get_vals(
const std::vector<char>& vars,
const double R,
const double T,
const double rho,
const Array &z)
const{
181 auto dTrecipdT = -Trecip*Trecip;
192 auto alpha = [&](){
return A00; };
193 auto dalphadTrecip = [&](){
return A10/Trecip; };
194 auto dalphadrho = [&](){
return A01/rho; };
197 auto a = [&](){
return alpha()*R*T; };
198 auto dadTrecip = [&](){
return R/(Trecip*Trecip)*(Trecip*dalphadTrecip()-alpha()); };
199 auto dadrho = [&](){
return R/Trecip*(dalphadrho()); };
201 for (
auto i = 0; i < vars.size(); ++i){
208 v(i) = rho*rho*dadrho();
break;
210 v(i) = Trecip*Trecip*dadTrecip();
break;
212 v(i) = a() + Trecip*dadTrecip() + rho*dadrho();
break;
214 v(i) = a() + Trecip*dadTrecip();
break;
216 throw std::invalid_argument(
"bad var: " + std::to_string(vars[i]));
222static_assert(std::is_copy_constructible_v<AlphaModel>);
238 const std::vector<char> vars;
239 const Eigen::Array2d vals;
241 const Eigen::ArrayXd z;
242 Eigen::Array2d Trho, r;
245 std::tuple<bool, bool> relative_error;
246 const std::vector<std::shared_ptr<StoppingCondition>> stopping_conditions;
248 int step_counter = 0;
250 std::vector<int> nonconstant_indices;
254 NRIterator(
const AlphaModel& alphamodel,
const std::vector<char>& vars,
const Eigen::Array2d& vals,
double T,
double rho,
const Eigen::Ref<const Eigen::ArrayXd>& z,
const std::tuple<bool, bool> &relative_error,
const std::vector<std::shared_ptr<StoppingCondition>> stopping_conditions) : alphamodel(alphamodel), vars(vars), vals(vals), Trho((Eigen::Array2d() << T,rho).finished()), z(z), R(alphamodel.get_R(z)), relative_error(relative_error), stopping_conditions(stopping_conditions) {
255 if(!(vars[0] ==
'T' || vars[1] ==
'T')){ nonconstant_indices.push_back(0); }
256 if(!(vars[0] ==
'D' || vars[1] ==
'D')){ nonconstant_indices.push_back(1); }
257 isTD = (nonconstant_indices.size() == 0);
262 std::vector<char>
get_vars()
const {
return vars; }
266 auto get_T()
const {
return Trho(0); }
279 Trho = (Eigen::Array2d() << T, rho).finished();
289 auto A = alphamodel.get_deriv_mat2(T, rho, z);
294 return std::make_tuple((im.J.matrix().fullPivLu().solve((-(im.v-vals)).matrix())).eval(), im);
304 Eigen::Array2d r = im.v-vals;
305 if (std::get<0>(relative_error)){ r(0) /= vals(0);}
306 if (std::get<1>(relative_error)){ r(1) /= vals(1);}
311 if (std::get<0>(relative_error)){ im.J.row(0) /= vals(0);}
312 if (std::get<1>(relative_error)){ im.J.row(1) /= vals(1);}
317 Eigen::Array2d r = alphamodel.get_vals(vars, R, T, rho, z)-vals;
318 if (std::get<0>(relative_error)){ r(0) /= vals(0);}
319 if (std::get<1>(relative_error)){ r(1) /= vals(1);}
320 return r.abs().maxCoeff();
324 return r.abs().maxCoeff();
341 if (std::get<0>(relative_error)){ r(0) /= vals(0); im.J.row(0) /= vals(0); }
342 if (std::get<1>(relative_error)){ r(1) /= vals(1); im.J.row(1) /= vals(1); }
344 Eigen::Array2d dTrho = im.J.matrix().fullPivLu().solve((-r).matrix());
351 for (
auto K = 0; K < N; ++K){
355 if (std::get<0>(relative_error)){ r(0) /= vals(0); im.J.row(0) /= vals(0); }
356 if (std::get<1>(relative_error)){ r(1) /= vals(1); im.J.row(1) /= vals(1); }
358 Eigen::Array2d dTrho = im.J.matrix().fullPivLu().solve((-r).matrix());
363 const StoppingData data{K, Trho, dTrho, r, nonconstant_indices};
364 for (
auto& condition : stopping_conditions){
366 auto this_reason = condition->stop(data);
367 if (this_reason != s::keep_going){
368 stop =
true; reason = this_reason; msg = condition->desc();
break;
390 auto tic = std::chrono::steady_clock::now();
393 for (
auto K = 0; K < N; ++K){
397 im.J.col(1) *= Trho(1);
398 if (std::get<0>(relative_error)){ r(0) /= vals(0); im.J.row(0) /= vals(0); }
399 if (std::get<1>(relative_error)){ r(1) /= vals(1); im.J.row(1) /= vals(1); }
411 using my_float = boost::multiprecision::number<boost::multiprecision::cpp_bin_float<164U>>;
412 Eigen::Matrix<my_float, 2, 2> Jmp = im.J.cast<my_float>();
413 Eigen::Vector<my_float, 2> rmp = r.cast<my_float>();
414 step = Jmp.fullPivLu().solve(-rmp).cast<
double>();
415 Eigen::Array<my_float, 2, -1> newvals = (Trho.cast<my_float>() + Jmp.fullPivLu().solve(-rmp).array());
417 Eigen::Array2d new_double = (Trho + im.J.matrix().fullPivLu().solve((-r).matrix()).array());
418 std::cout <<
"-- " << ((newvals-new_double.cast<my_float>())/Trho.cast<my_float>()).cast<double>() << std::endl;
421 step = im.J.matrix().fullPivLu().solve((-r).matrix());
423 Eigen::Array2d dTrho = (Eigen::Array2d() << step(0), Trho(1)*(exp(step(1))-1)).finished();
427 const StoppingData data{K, Trho, dTrho, r, nonconstant_indices};
428 for (
auto& condition : stopping_conditions){
430 auto this_reason = condition->stop(data);
431 if (this_reason != s::keep_going){
432 stop =
true; reason = this_reason; msg = condition->desc();
break;
439 if(nonconstant_indices.size() == 0){
463 auto toc = std::chrono::steady_clock::now();
473 Eigen::Array2d vals_current = im.v;
474 double x_current = vals_current(0);
475 double y_current = vals_current(1);
478 double x_target = vals(0);
479 double y_target = vals(1);
480 auto dxdt = (x_target-x_current)/(1.0-0.0);
481 auto dydt = (y_target-y_current)/(1.0-0.0);
485 for (
auto i = 0U; i < N; ++i){
487 auto dxdT__rho = im.J(0, 0);
488 auto dxdrho__T = im.J(0, 1);
489 auto dydT__rho = im.J(1, 0);
490 auto dydrho__T = im.J(1, 1);
492 auto dxdT__y = dxdT__rho - dxdrho__T*dydT__rho/dydrho__T;
493 auto dxdrho__y = dxdrho__T - dxdT__rho*dydrho__T/dydT__rho;
495 auto dydT__x = dydT__rho - dydrho__T*dxdT__rho/dxdrho__T;
496 auto dydrho__x = dydrho__T - dydT__rho*dxdrho__T/dxdT__rho;
499 double dTdt = dxdt/dxdT__y + dydt/dydT__x;
500 double drhodt = dxdt/dxdrho__y + dydt/dydrho__x;
506 std::cout << i <<
"," << (im.v-vals).abs().maxCoeff() << std::endl;
509 return std::make_tuple(T, rho, im.v(0), im.v(1));
std::shared_ptr< AbstractModel > model_residual
auto get_A00A10A01(double T, double rho, const Z &z) const
std::shared_ptr< AbstractModel > model_ideal_gas
auto get_R(const Z &z) const
auto get_R(const std::vector< double > &z) const
auto get_vals(const std::vector< char > &vars, const double R, const double T, const double rho, const Array &z) const
A convenience function for calculation of Jacobian terms of the form and where is one of the therm...
Eigen::Array33d get_deriv_mat2(double T, double rho, const std::vector< double > &z) const
Eigen::Array33d get_deriv_mat2(double T, double rho, const Z &z) const
MaxAbsErrorCondition(double threshold)
StoppingConditionReason stop(const StoppingData &data) override
std::string desc() override
std::string desc() override
MinRelStepsizeCondition(double threshold)
StoppingConditionReason stop(const StoppingData &data) override
Eigen::ArrayXd get_molefrac() const
Return the current mole fractions.
auto calc_maxabsr(double T, double rho) const
Calculate the maximum absolute value of the values in r.
std::vector< char > get_vars() const
Return the variables that are being used in the iteration.
auto calc_J(double T, double rho) const
auto get_T() const
Return the current temperature.
auto path_integration(double T, double rho, std::size_t N)
auto get_rho() const
Return the current molar density.
auto calc_vals(double T, double rho) const
std::string get_message() const
Return the current message relaying information about success or failure of the iteration.
auto take_steps(int N, bool apply_stopping=true)
auto calc_just_step(double T, double rho) const
auto get_nonconstant_indices() const
Get the indices of the nonconstant variables.
auto calc_step(double T, double rho) const
Eigen::Array2d get_vals() const
Return the target values to be obtained.
auto calc_matrices(double T, double rho) const
void reset(double T, double rho)
NRIterator(const AlphaModel &alphamodel, const std::vector< char > &vars, const Eigen::Array2d &vals, double T, double rho, const Eigen::Ref< const Eigen::ArrayXd > &z, const std::tuple< bool, bool > &relative_error, const std::vector< std::shared_ptr< StoppingCondition > > stopping_conditions)
auto get_maxabsr() const
Get the maximum absolute value of residual vector, using the cached value for r.
int get_step_count() const
Return the current step counter.
auto calc_r(double T, double rho) const
auto take_steps_logrho(int N)
StoppingConditionReason stop(const StoppingData &data) override
std::string desc() override
StoppingConditionReason stop(const StoppingData &data) override
std::string desc() override
std::string desc() override
StepCountErrorCondition(int Nmax)
StoppingConditionReason stop(const StoppingData &data) override
virtual StoppingConditionReason stop(const StoppingData &)=0
virtual ~StoppingCondition()=default
virtual std::string desc()=0
auto build_iteration_Jv(const std::vector< char > &vars, const Eigen::Array< double, 3, 3 > &A, const double R, const double T, const double rho, const Array &z)
A convenience function for calculation of Jacobian terms of the form and where is one of the therm...
StoppingConditionReason reason
const Eigen::Array2d & r
The set of residual functions.
const std::vector< int > & nonconstant_indices
The indices where the independent variable can be varied (are not T or rho)
const Eigen::Array2d & dx
The complete set of steps in independent variables.
const int N
The number of steps that have been taken so far.
const Eigen::Array2d & x
The complete set of independent variables.