Program Listing for File rksolver.hpp¶
↰ Return to documentation for file (/home/docs/checkouts/readthedocs.org/user_builds/oscode/checkouts/stable/include/rksolver.hpp
)
#pragma once
#include "system.hpp"
class RKSolver
{
private:
// Frequency and friction term
std::function<std::complex<double>(double)> w;
std::function<std::complex<double>(double)> g;
// Butcher tablaus
Eigen::Matrix<double,5,5> butcher_a5;
Eigen::Matrix<double,3,3> butcher_a4;
Eigen::Matrix<double,6,1> butcher_b5, butcher_c5, dense_b5;
Eigen::Matrix<double,4,1> butcher_b4, butcher_c4;
// Current values of w, g
std::complex<double> wi, gi;
public:
de_system *de_sys_;
//std::function<std::complex<double>(double)> w;
// constructors
RKSolver();
RKSolver(de_system &de_sys);
// grid of ws, gs
Eigen::Matrix<std::complex<double>,6,1> ws;
Eigen::Matrix<std::complex<double>,6,1> gs;
Eigen::Matrix<std::complex<double>,5,1> ws5;
Eigen::Matrix<std::complex<double>,5,1> gs5;
// single step function
Eigen::Matrix<std::complex<double>,2,2> step(std::complex<double>, std::complex<double>, double, double);
// ODE to solve
Eigen::Matrix<std::complex<double>,1,2> f(double t, const Eigen::Matrix<std::complex<double>,1,2> &y);
// For dense output
Eigen::Matrix<std::complex<double>,6,2> k5;
Eigen::Matrix<std::complex<double>,1,2> dense_point(std::complex<double> x, std::complex<double> dx, const Eigen::Matrix<std::complex<double>,6,2> &k5);
Eigen::Matrix<std::complex<double>,7,2> k_dense;
Eigen::Matrix<double,7,4> P_dense;
void dense_step(double t0, double h0, std::complex<double> y0, std::complex<double> dy0, const std::list<double> &dots, std::list<std::complex<double>> &doxs, std::list<std::complex<double>> &dodxs);
// Experimental continuous representation of solution
Eigen::Matrix<std::complex<double>,7,1> x_vdm;
};
RKSolver::RKSolver(){
};
RKSolver::RKSolver(de_system &de_sys){
de_sys_ = &de_sys;
if(de_sys_->is_interpolated == 0){
w = de_sys.w;
g = de_sys.g;
}
// Set Butcher tableaus
RKSolver::butcher_a5 << 0.1174723380352676535740,0,0,0,0,
-0.1862479800651504276304,0.5436322218248278794734,0,0,0,
-0.6064303885508280518989,1,0.2490461467911506000559,0,0,
2.899356540015731406420,-4.368525611566240669139,2.133806714786316899991,0.2178900187289247091542,0,
18.67996349995727204273,-28.85057783973131956546,10.72053408420926869789,1.414741756508049078612,-0.9646615009432702537787;
RKSolver::butcher_a4 << 0.172673164646011428100,0,0,
-1.568317088384971429762,2.395643923738960001662,0,
-8.769507466172720011410,10.97821961869480000808,-1.208712152522079996671;
RKSolver::butcher_b5 << 0.1127557227351729739820,0,0.5065579732655351768382,0.04830040376995117617928,0.3784749562978469803166,-0.04608905606850630731611;
RKSolver::dense_b5 << 0.2089555395,0.,0.7699501023,0.009438629906,-0.003746982422,0.01540271068;
RKSolver::butcher_c5 << 0,0.117472338035267653574,0.357384241759677451843,0.642615758240322548157,0.882527661964732346426,1;
RKSolver::butcher_b4 << -0.08333333333333333333558,0.5833333333333333333357,0.5833333333333333333356,-0.08333333333333333333558;
RKSolver::butcher_c4 << 0,0.172673164646011428100,0.827326835353988571900,1;
RKSolver::P_dense << 1. , -2.48711376, 2.42525041, -0.82538093,
0. , 0. , 0. , 0.,
0. , 3.78546138, -5.54469086, 2.26578746,
0. , -0.27734213, 0.74788587, -0.42224334,
0. , -2.94848704, 7.41087391, -4.08391191,
0. , 0.50817346, -1.20070313, 0.64644062,
0. , 1.4193081 , -3.8386162 , 2.4193081;
};
Eigen::Matrix<std::complex<double>,1,2> RKSolver::f(double t, const Eigen::Matrix<std::complex<double>,1,2> &y){
// std::cout << "Are we interpolating? " << de_sys_->is_interpolated << std::endl;
if(de_sys_->is_interpolated == 1){
if(de_sys_->islogw_)
wi = de_sys_->Winterp.expit(t);
else
wi = de_sys_->Winterp(t);
if(de_sys_->islogg_)
gi = de_sys_->Ginterp.expit(t);
else
gi = de_sys_->Ginterp(t);
}
else{
wi = w(t);
gi = g(t);
}
Eigen::Matrix<std::complex<double>,1,2> result;
result << y[1], -wi*wi*y[0]-2.0*gi*y[1];
return result;
};
Eigen::Matrix<std::complex<double>,1,2> RKSolver::dense_point(std::complex<double> x, std::complex<double> dx, const Eigen::Matrix<std::complex<double>,6,2> &k5){
Eigen::Matrix<std::complex<double>,1,2> ydense;
ydense << x, dx;
for(int j=0; j<=5; j++)
ydense += 0.5866586817*dense_b5(j)*k5.row(j);
return ydense;
};
void RKSolver::dense_step(double t0, double h0, std::complex<double> y0, std::complex<double> dy0, const std::list<double> &dots, std::list<std::complex<double>> &doxs, std::list<std::complex<double>> &dodxs){
int docount = dots.size();
double h = h0;
double sig, sig2, sig3, sig4;
Eigen::Matrix<std::complex<double>,2,4> Q_dense = k_dense.transpose()*P_dense;
Eigen::MatrixXd R_dense(4,docount);
Eigen::MatrixXcd Y_dense(2,docount);
int colcount = 0;
for(auto it=dots.begin(); it!=dots.end(); it++){
// Transform intermediate points to be in (-1,1):
sig = (*it - t0)/h;
sig2 = sig*sig;
sig3 = sig2*sig;
sig4 = sig3*sig;
R_dense.col(colcount) << sig, sig2, sig3, sig4;
colcount += 1;
}
Y_dense = Q_dense*R_dense;
auto it = doxs.begin();
auto dit = dodxs.begin();
for(int j=0; j<docount; j++){
*it = y0 + Y_dense.row(0)(j);
*dit = dy0 + Y_dense.row(1)(j);
it++;
dit++;
}
};
Eigen::Matrix<std::complex<double>,2,2> RKSolver::step(std::complex<double> x0, std::complex<double> dx0, double t0, double h){
Eigen::Matrix<std::complex<double>,1,2> y0, y, y4, y5, delta, k5_i, k4_i;
y4 = Eigen::Matrix<std::complex<double>,1,2>::Zero();
y0 << x0, dx0;
y5 = y4;
// TODO: resizing of ws5, gs5, insertion
Eigen::Matrix<std::complex<double>,4,2> k4;
Eigen::Matrix<std::complex<double>,2,2> result;
// std::cout << "Set up RK step" << std::endl;
k5.row(0) = h*f(t0, y0);
// std::cout << "Asked for f" << std::endl;
ws(0) = wi;
gs(0) = gi;
for(int s=1; s<=5; s++){
y = y0;
for(int i=0; i<=(s-1); i++)
y += butcher_a5(s-1,i)*k5.row(i);
k5_i = h*f(t0 + butcher_c5(s)*h, y);
k5.row(s) = k5_i;
ws(s) = wi;
gs(s) = gi;
}
k4.row(0) = k5.row(0);
ws5(0) = ws(0);
gs5(0) = gs(0);
for(int s=1; s<=3; s++){
y = y0;
for(int i=0; i<=(s-1); i++)
y += butcher_a4(s-1,i)*k4.row(i);
k4_i = h*f(t0 + butcher_c4(s)*h, y);
k4.row(s) = k4_i;
ws5(s) = wi;
gs5(s) = gi;
}
for(int j=0; j<=5; j++)
y5 += butcher_b5(j)*k5.row(j);
for(int j=0; j<=3; j++)
y4 += butcher_b4(j)*k4.row(j);
delta = y5 - y4;
y5 += y0;
result << y5, delta;
// Add in missing w, g at t+h/2
ws5(4) = ws5(3);
ws5(3) = ws5(2);
gs5(4) = gs5(3);
gs5(3) = gs5(2);
if(de_sys_->is_interpolated == 1){
if(de_sys_->islogw_)
ws5(2) = de_sys_->Winterp.expit(t0+h/2);
else
ws5(2) = de_sys_->Winterp(t0+h/2);
if(de_sys_->islogg_)
gs5(2) = de_sys_->Ginterp.expit(t0+h/2);
else
gs5(2) = de_sys_->Ginterp(t0+h/2);
}
else{
ws5(2) = w(t0+h/2);
gs5(2) = g(t0+h/2);
}
// Fill up k_dense matrix for dense output
for(int i=0; i<=5; i++)
k_dense.row(i) = k5.row(i);
k_dense.row(6) = h*f(t0+h,y5);
// Experimental continuous output
Eigen::Matrix<std::complex<double>,1,4> Q_dense = (k_dense.transpose()*P_dense).row(0);
x_vdm.tail(6) << Q_dense(0), Q_dense(1), Q_dense(2), Q_dense(3), 0.0, 0.0;
x_vdm(0) = x0;
return result;
};