BOOST:ODEINT Sudden Iteration stop - c++

I'm new in the world of C++ and I'm having some trouble with the boost library. In my problem I want to solve a ODE-System with 5 equations. It isn't a stiff problem. As iterative method I used both integreate(rhs, x0, t0, tf, size_step, write_output) and integreate_adaptive(stepper, sys, x0, t0, tf, size_step, write_output). Both these method actually integrate the equations but giving me non-sense results changing the size of the step from 0.001 to 5 almost randomly. The equations and data are correct. What can I do to fix this problem? Here is the code:
#include <iostream>
#include <vector>
#include <boost/numeric/odeint.hpp>
#include <fstream>
#include <boost/array.hpp>
using namespace std;
using namespace boost::numeric::odeint;
//DATA
double Lin = 20000; // kg/h
double Gdry = 15000; // kg/h
double P = 760; // mmHg
double TinH2O = 50; // °C
double ToutH2O = 25; // °C
double Tinair = 20; // °C
double Z = 0.5; // relative humidity
double Cu = 0.26; // kcal/kg*K
double CpL = 1; // kcal/kg*K
double DHev = 580; // kcal/kg
double hga = 4000; // kcal/m/h/K
double hla = 30000; // kcal/m/h/K
double A = -49.705; // Pev 1st coeff mmHg vs °C
double B = 2.71; // Pev 2nd coeff mmHg vs °C
double Usair = 0.62*(A + B*Tinair) / P;
double Uair = Z*Usair;
double Kua = hga / Cu;
double L0 = 19292; // kg/h
typedef vector< double > state_type;
vector <double> pack_height;
vector <double> Umidity;
vector <double> T_liquid;
vector <double> T_gas;
vector <double> Liquid_flow;
vector <double> Gas_flow;
void rhs(const state_type& x , state_type& dxdt , const double z )
{// U Tl Tg L G
double Ti = (hla*x[1] + hga*x[2] + Kua*DHev*(x[0] - 0.62*A / P)) / (hla + hga + Kua*DHev*0.62*B / P);
double Ui = 0.62*(A + B*Ti) / P;
dxdt[0] = Kua*(Ui - x[0]) / Gdry / 100;
dxdt[1] = hla*(x[1] - Ti) / x[3] / CpL / 100;
dxdt[2] = hga*(Ti - x[2]) / Gdry / Cu / 100;
dxdt[3] = Kua*(Ui - x[0]) / 100;
dxdt[4] = Kua*(Ui - x[0]) / 100;
}
void write_output(const state_type& x, const double z)
{
pack_height.push_back(z);
Umidity.push_back(x[0]);
T_liquid.push_back(x[1]);
T_gas.push_back(x[2]);
Liquid_flow.push_back(x[3]);
Gas_flow.push_back(x[4]);
cout << z << " " << x[0] << " " << x[1] << " " << x[2] << " " << x[3] << " " << x[4] << endl;
}
int main()
{
state_type x(5);
x[0] = Uair;
x[1] = ToutH2O;
x[2] = Tinair;
x[3] = L0;
x[4] = Gdry;
double z0 = 0.0;
double zf = 5.5;
double stepsize = 0.001;
integrate( rhs , x , z0 , zf , stepsize , write_output );
return 0;
}
And this is the final results that i get from the prompt:
0 0.00183349 25 20 19292 15000
0.001 0.00183356 25 20 19292 15000
0.0055 0.0018339 25.0002 20.0001 19292 15000
0.02575 0.00183542 25.001 20.0007 19292 15000
0.116875 0.00184228 25.0046 20.003 19292.1 15000.1
0.526938 0.00187312 25.0206 20.0135 19292.6 15000.6
2.37222 0.00201203 25.0928 20.0608 19294.7 15002.7
5.5 0.00224788 25.2155 20.142 19298.2 15006.2
Only the first iteration has the right-asked stepsize.. and obiviously the solution is not the right one.. what can i do? Thank you in advance. :)

If you read the documentation, then you will find that the constant step-size routines are integrate_const and integrate_n_steps, or possibly integrate_adaptive with a non-controlled stepper.
The short call to integrate uses the standard dopri5 stepper with adaptive step size, so that the changing step size is no surprise. You could possibly use the dense output of the stepper to interpolate values at equidistant times.

Related

Converting CppAD::AD<double> to double in cpp

I'm using CppAD with Ipopt. In some places I have to typecast the AD format to its base format that is double. I have used CppAD::Value(AD var) it gives me output in double format.
But considering line no.27 the code is fine during compile time. Its showing the following error in runtime. The error is :
cppad-20160000.1 error from a known source:
Value: argument is a variable (not a parameter)
Error detected by false result for
Parameter(x)
at line 89 in the file
/usr/include/cppad/local/value.hpp
I have attached the code I'm running for verification. Kindly help. please install Ipopt before running the code.
The type of value is still CppAD::AD . But the Value() is not working.
#include <cppad/ipopt/solve.hpp>
#include <iostream>
namespace {
using CppAD::AD;
class FG_eval {
public:
typedef CPPAD_TESTVECTOR( AD<double> ) ADvector;
void operator()(ADvector& fg, const ADvector& x)
{ assert( fg.size() == 3 );
assert( x.size() == 4 );
// Fortran style indexing
AD<double> x1 = x[0];
AD<double> x2 = x[1];
AD<double> x3 = x[2];
AD<double> x4 = x[3];
// f(x)
fg[0] = x1 * x4 * (x1 + x2 + x3) + x3;
// g_1 (x)
fg[1] = x1 * x2 * x3 * x4;
// g_2 (x)
fg[2] = x1 * x1 + x2 * x2 + x3 * x3 + x4 * x4;
// help on this line
std::cout << CppAD::Value(x1) << std::endl;
//
return;
}
};
}
bool get_started()
{ bool ok = true;
size_t i;
typedef CPPAD_TESTVECTOR( double ) Dvector;
// number of independent variables (domain dimension for f and g)
size_t nx = 4;
// number of constraints (range dimension for g)
size_t ng = 2;
// initial value of the independent variables
Dvector xi(nx);
xi[0] = 1.0;
xi[1] = 5.0;
xi[2] = 5.0;
xi[3] = 1.0;
// lower and upper limits for x
Dvector xl(nx), xu(nx);
for(i = 0; i < nx; i++)
{ xl[i] = 1.0;
xu[i] = 5.0;
}
// lower and upper limits for g
Dvector gl(ng), gu(ng);
gl[0] = 25.0; gu[0] = 1.0e19;
gl[1] = 40.0; gu[1] = 40.0;
// object that computes objective and constraints
FG_eval fg_eval;
// options
std::string options;
// turn off any printing
options += "Integer print_level 0\n";
options += "String sb yes\n";
// maximum number of iterations
options += "Integer max_iter 10\n";
// approximate accuracy in first order necessary conditions;
// see Mathematical Programming, Volume 106, Number 1,
// Pages 25-57, Equation (6)
options += "Numeric tol 1e-6\n";
// derivative testing
options += "String derivative_test second-order\n";
// maximum amount of random pertubation; e.g.,
// when evaluation finite diff
options += "Numeric point_perturbation_radius 0.\n";
// place to return solution
CppAD::ipopt::solve_result<Dvector> solution;
// solve the problem
CppAD::ipopt::solve<Dvector, FG_eval>(
options, xi, xl, xu, gl, gu, fg_eval, solution
);
//
// Check some of the solution values
//
ok &= solution.status == CppAD::ipopt::solve_result<Dvector>::success;
//
double check_x[] = { 1.000000, 4.743000, 3.82115, 1.379408 };
double check_zl[] = { 1.087871, 0., 0., 0. };
double check_zu[] = { 0., 0., 0., 0. };
double rel_tol = 1e-6; // relative tolerance
double abs_tol = 1e-6; // absolute tolerance
for(i = 0; i < nx; i++)
{ ok &= CppAD::NearEqual(
check_x[i], solution.x[i], rel_tol, abs_tol
);
ok &= CppAD::NearEqual(
check_zl[i], solution.zl[i], rel_tol, abs_tol
);
ok &= CppAD::NearEqual(
check_zu[i], solution.zu[i], rel_tol, abs_tol
);
}
return ok;
}
int main()
{
get_started();
return 0;
}
cmakelists.txt
cmake_minimum_required(VERSION 3.5)
project(jnk)
add_compile_options(-std=c++11)
add_executable(${PROJECT_NAME} testCppAD.cpp)
target_link_libraries(${PROJECT_NAME}
ipopt z uv
)
I found out the answer. We have to use an inbuilt function CppAD::Var2Par() before using CppAD::Value(). Will work.

4th Order Adams-Moulton Method C++

I am trying to solve an ODE using 4th Order Runge Kutta and the 4th Order Adams-Moulton Method. I iterate over a couple of thousand timesteps and it seems to hold fine when the values are constant(first 50 or so) However, the very first iteration when a change in input value jumps(current(I) changes from 0 to 1) it won't converge.
In order to satisfy the 4th Order Adams-Moulton Method I have split each timestep in the main function into 5 smaller timesteps so the 5th inner step will equal the next time step (0.1s) in the main function.
I will be very grateful for any advice/help!!
The code is below
#include <iostream>
#include <cmath>
using namespace std;
double state_deriv(double Vc,double I, double OCV1, double C, double Rct)
{
double newVc = (OCV1 - Vc) / (C * Rct) - (I / C);
return newVc;
}
double predict(double Vc,double Vc_[],double dt,double I_[],double OCV1_[],double C_[],double Rct_[])
{
double fn[4];
fn[0] = state_deriv(Vc_[0], I_[0],OCV1_[0],C_[0],Rct_[0]);
fn[1] = state_deriv(Vc_[1], I_[1],OCV1_[1],C_[1],Rct_[1]);
fn[2] = state_deriv(Vc_[2], I_[2],OCV1_[2],C_[2],Rct_[2]);
fn[3] = state_deriv(Vc_[3], I_[3],OCV1_[3],C_[3],Rct_[3]);
// value of next y(predicted) is returned
double y1p = Vc_[3] + (dt/24)*(55*fn[3] - 59*fn[2] + 37 *fn[1] - 9 *fn[0]);
return y1p;
}
double correct(double Vc,double Vc_[],double Vc1,double dt,double I_[],double OCV1_[],double C_[],double Rct_[])
{
double e = 0.0001;
double Vc1c = Vc1;
double fn[4];
fn[1] = state_deriv(Vc_[1], I_[1],OCV1_[1],C_[1],Rct_[1]);
fn[2] = state_deriv(Vc_[2], I_[2],OCV1_[2],C_[2],Rct_[2]);
fn[3] = state_deriv(Vc_[3], I_[3],OCV1_[3],C_[3],Rct_[3]);
do {
Vc1 = Vc1c;
fn[4] = state_deriv(Vc1, I_[4],OCV1_[4],C_[4],Rct_[4]);
Vc1c = Vc_[3] + dt/24*(9*fn[4] + 19*fn[3] - 5*fn[2] + fn[1]);
} while (fabs(Vc1c - Vc1) > e);
// every iteration is correcting the value
// of state deriv using average slope
return Vc1c;
}
double predictor_corrector(double Vc, double dt, double I[], double* OCV1, double* C, double* Rct)
{
//double x = time[0];
//double xn = time[1];
double h = dt;
//4th order RKK TO predict 4 values
double I_[4],OCV1_[5],C_[5],Rct_[5];
I_[0] = I[0];
OCV1_[0] = OCV1[0];
C_[0] = *C;
Rct_[0] = *Rct;
I_[4] = I[1];
OCV1_[4] = OCV1[1];
C_[4] = *C;
Rct_[4] = *Rct;
double newdt;
for(int i = 1;i<4;i++){
newdt = i * dt/5;
I_[i] = I_[0] + (I[1]-I[0]) * (newdt/dt);
OCV1_[i] = OCV1_[0] + (OCV1[1] - OCV1[0])*(newdt/dt);
Rct_[i] = *Rct;
C_[i] = *C;
}
//now do rk4 on each step
double k1,k2,k3,k4;
double Vc_[4];
Vc_[0] = Vc;
for(int i = 1;i<4;i++) {
// 4th order runge kutta
k1 = dt/4 * state_deriv(Vc_[i-1], *I, *OCV1, *C, *Rct);
k2 = dt/4 * state_deriv(Vc_[i-1]+k1/2.0, I_[i], OCV1_[i], *C, *Rct);
k3 = dt/4 * state_deriv(Vc_[i-1]+k2/2.0, I_[i], OCV1_[i], *C, *Rct);
k4 = dt/4 * state_deriv(Vc_[i-1]+k3, I_[i], OCV1_[i], *C, *Rct);
Vc_[i] = Vc_[i-1] + (1.0 / 6.0) * (k1 + 2 * k2 + 2 * k3 + k4);
}
double y1p = predict(Vc,Vc_,dt/4,I_,OCV1_,C_,Rct_);
double y1c = correct(Vc,Vc_,y1p,dt/4,I_,OCV1_,C_,Rct_);
Vc = y1c;
cout << Vc << endl;
return Vc;
}
int main()
{
double R1 = 0.0315973;
double C = 0.00100284;
double Vc[5];
double OCV1[5];
double I[5];
Vc[0] = 4.15;
double dt = 0.1;
for(int i=0;i<3;i++){
OCV1[i] = 4.15;
I[i] = 0;
}
I[3]=I[4]=1;
OCV1[3] = 4.13;
OCV1[4] = 4.10;
double I_[2];
for(size_t i=1;i<4;i++){
Vc[i] = predictor_corrector(Vc[i-1],dt,&I[i-1],&OCV1[i-1],&C,&R1);
}
}

can't get same results Matlab generates

Take a look at the following transfer function:
With Matlab Simulink:
The result is
In State-space representation, the system can be modeled as follows:
In Matlab, we can model the system in the state-space representation:
which yields the following plot:
which is exactly the result generated by using transfer function. I'm trying to generate same results with odeint but failed. This is the code
#include <iostream>
#include <Eigen/Dense>
#include <boost/numeric/odeint.hpp>
#include <iomanip>
#include <fstream>
using namespace std;
using namespace boost::numeric::odeint;
typedef std::vector< double > state_type;
void equations(const state_type &y, state_type &dy, double x)
{
Eigen::MatrixXd A(3, 3), B(3,1);
/*
x = y[0]
dx = y[1] = dy[0]
ddx = y[2] = dy[1]
dddx = dy[2]
*/
const double r(1);
A << 0, 1, 0,
0, 0, 1,
-24, -26, -9;
B << 0, 0, 1;
//#####################( ODE Equations )################################
Eigen::MatrixXd X(3, 1), dX(3,1);
X << y[0], y[1], y[2];
dX = A*X + B*r;
dy[0] = dX(0,0);
dy[1] = dX(1,0);
dy[2] = dX(2,0);
}
int main(int argc, char **argv)
{
const double dt = 0.01;
runge_kutta_dopri5 < state_type > stepper;
state_type y(3);
// initial values
y[0] = 0.0; // x1
y[1] = 0.0; // x2
y[2] = 0.0; // x3
ofstream data("file.txt");
for (double t(0.0); t <= 5.0; t += dt){
data << t << " " << 2*y[0] << " " << 7*y[1] << " " << 1*y[2] << std::endl;
stepper.do_step(equations, y, t, dt);
}
return 0;
}
And this is the result for all state vector
None of the preceding variables match the results generated by Matlab. Any suggestions to fix this code?
Look at the expression you have for y. When you multiply a 1x3 matrix with a 3x1 matrix, the result should be a 1x1 matrix, where the value of the single element is the dot product of the two matrices. What you're currently doing is element-wise multiplication when you write to data instead of calculating the dot product.

Runge-Kutta algorithm C++

Below is my 4th order Runge-Kutta algorithm to solve a first order ODE. I am checking it against the wikipedia example found here to solve:
\frac{dx}{dt} = tan(x) + 1
Unfortunately it is out by a little bit. I have toyed around for a long while, but I can't find the error. The answer should be t = 1.1 and x = 1.33786352224364362. The below code gives t = 1.1 and x = 1.42223.
/*
This code is a 1D classical Runge-Kutta method. Compare to the Wikipedia page.
*/
#include <math.h>
#include <iostream>
#include <iomanip>
double x,t,K,K1,K2,K3,K4;
const double sixth = 1.0 / 6.0;
static double dx_dt(double t, double x){
return tan(x) + 1;
}
int main(int argc, const char * argv[]) {
/*======================================================================*/
/*===================== Runge-Kutta Method for ODE =====================*/
/*======================================================================*/
double t_initial = 1.0;// initial time
double x_initial = 1.0;// initial x position
double t_final = 1.1;// value of t wish to know x
double dt = 0.025;// time interval for updates
double halfdt = 0.5*dt;
/*======================================================================*/
while(t_initial < t_final){
/*============================ Runge-Kutta increments =================================*/
double K1 = dt*dx_dt( t_initial, x_initial );
double K2 = dt*dx_dt( t_initial + halfdt, x_initial + halfdt*K1 );
double K3 = dt*dx_dt( t_initial + halfdt, x_initial + halfdt*K2 );
double K4 = dt*dx_dt( t_initial + dt, x_initial + dt*K3 );
x_initial += sixth*(K1 + 2*(K2 + K3) + K4);
/*============================ prints =================================*/
std::cout << t_initial << std::setw(16) << x_initial << "\n";
/*============================ re-setting update conditions =================================*/
t_initial += dt;
/*======================================================================*/
}
std::cout<<"----------------------------------------------\n";
std::cout << "t = "<< t_initial << ", x = "<< x_initial << std::endl;
}/* main */
The problem is that the tableau used for your code is different than the one for the code you cited in wikipedia. The one you're using is this:
0 |
1/2 | 1/2
1/2 | 0 1/2
1 | 0 0 1
-------------------------------------
| 1/6 1/3 1/3 1/6
And the one used in wikipedia is
0 |
2/3 | 2/3
---------------------
| 1/4 3/4
Different tableaus will yield different results depending on the step-size, which is the way used to make sure that the step-size is good enough for a certain accuracy. However, when dt -> 0, then all tableaus are the same.
Besides all this, your code is wrong anyway even for RK4. The second part of the function should have halves, not 0.5*dt:
double K1 = dt*dx_dt( t_initial, x_initial );
double K2 = dt*dx_dt( t_initial + halfdt, x_initial + 0.5*K1 );
double K3 = dt*dx_dt( t_initial + halfdt, x_initial + 0.5*K2 );
double K4 = dt*dx_dt( t_initial + dt, x_initial + K3 );
You are making a rather usual mistake in trying to be overly correct and implement the two variants of the algorithm at once.
It should either be
k2 = dt*f(t+0.5*dt, x+0.5*k1)
or
k2 = f(t+0.5*dt, x+0.5*dt*k1)
the other ks accordingly.
Note that in both cases the slope fonly gets multiplied with dt once.
I think you are including one too many increments and have introduced problems by rearranging the mathematics. Try this:
#include <math.h>
#include <iostream>
#include <iomanip>
static double dx_dt(double t, double x)
{
return tan(x) + 1;
}
int main(int argc, const char * argv[])
{
double t = 1.0;
double t_end = 1.1;
double y = 1.0;
double h = 0.025;
std::cout << std::setprecision(16);
int n = static_cast<int>((t_end - t) / h);
for (int i = 0; i < n; i++)
{
double k1 = dx_dt(t, y);
double k2 = dx_dt(t + h / 2.0, y + h*k1 / 2.0);
double k3 = dx_dt(t + h / 2.0, y + h*k2 / 2.0);
double k4 = dx_dt(t + h, y + h*k3);
y += (k1 + 2 * k2 + 2 * k3 + k4) * h / 6.0;
std::cout << t << ": " << y << std::endl;
t += h;
}
std::cout << "----------------------------------------------\n";
std::cout << "t = " << t << ", x = " << y << std::endl;
std::getchar();
}
I precalculate how many times to do the iteration, this avoids a few different issues. Also as others have mentioned, the worked example on wikipedia is for a two stage variant of the algorithm.
I've taken the liberty of changing the variable names to match wikipedia. A good tip is always match the naming of your reference text until the thing works.

Rcpp NumericalMatrix data type, global declaration

I'm fairly new with C++ and I'm trying to use it via Rcpp to speed up my R code.
The below code integrates from from t0 to t1- this is done in the "lorenz" function. Test4 integrates using "lorenz" "counts" number of times. However at time "t1" the state of the system is modified in "write_lorenz" before the system is rerun and this is where the problem is. If I run the same program over and over again by calling test4 from R, printing to the screen always produces the same result, however, my returned matrix "u" does not, and seems to eventually converge to whatever "t1" is which is the problem.
My input values don't change so I'm wondering if there a memory leak, or if something else is going on, how to fix it.
Also I'm wondering if my initialization of "u" is incorrect and I should be using the "new" command.
What I tried was
NumericMatrix* u = NULL;
*u = new NumericMatrix;
and then I tried accessing the elements of the matrix as *u(1,2) for instance, but accessing the elements this way caused an error saying u was not a function.
Any help would be greatly appreciated
I modified this code from the following site
http://headmyshoulder.github.io/odeint-v2/examples.html
so I could use it with Rcpp
//###################################R Code ###############################
library(Rcpp)
sourceCpp("test4.cpp")
sigma <- 10.0
R <-28.0
b <- 8.0 / 3.0
a2 <- c(10.0 , 1.0 , 1.0) #initial conditions X0,I0,Y0
L2 <- c(0.0 , 2.0 , 0.1) #initial time, kick time, error
counts <- 2
kick <-1.0; # kick size
pars <-c(sigma,R,b,kick)
test4(a=a,L2=L2,counts=counts,pars= pars)
// C ++ code
//[[Rcpp::depends(BH)]]
//[[Rcpp::depends(RcppEigen)]]
//[[Rcpp::plugins("cpp11")]]
#include <Rcpp.h>
#include <RcppEigen.h>
#include <math.h>
#include <boost/array.hpp>
#include <boost/numeric/odeint.hpp>
#include <boost/algorithm/string.hpp>
using namespace boost::numeric::odeint;
using namespace std;
using namespace Rcpp;
using namespace Eigen;
double sigma =0;
double e =0;
double b =0 ;
double t0 =0;
double t1 = 0;
double kick =0;
double X0 = 0;
double I0 =0;
double Y0 =0;
double N = 0;
int counter =0;
typedef boost::array< double , 3 > state_type;
NumericMatrix u(4,5);
void lorenz( const state_type &x , state_type &dxdt , double t )
{
dxdt[0] = sigma * ( x[1] - x[0] );
dxdt[1] = e * x[0] - x[1] - x[0] * x[2];
dxdt[2] = -b * x[2] + x[0] * x[1];
}
void write_lorenz( const state_type &x , const double t )
{
if(t==t1){
X0 = x[0];
I0 = x[1];
Y0 = x[2];
N = X0+I0+Y0;
X0 = X0 + exp(kick*N);
counter++;
//for some reason cout and u don't match for multiple runs of the
//program
cout << t << '\t' << X0 << '\t' << I0 << '\t' << Y0 << endl;
u(counter,0) = t;
u(counter,1) = X0;
u(counter,2) = I0;
u(counter,3) = Y0;
}
}
// [[Rcpp::export]]
NumericMatrix test4(NumericVector a, NumericVector L2,int counts,NumericVector pars)
{
double error; // control integration error
// initialize model parameters
//maybe these should be parenthesis?
sigma = pars[0]; //# average per capita birh rate 1-10(the mean is 4.7)
e = pars[1]; // # per capita average growth rate
b= pars[2];
kick = pars[3]; // kick size
//cout << sigma << R << b << kick << endl;
//myfile.open (ST);
X0 = a[0]; I0 =a[1]; Y0 = a[2];
int i = 0;
t0 = L2[0];
t1 = L2[1];
error = L2[2];
u(0,0) = t0;
u(0,1) = X0;
u(0,2) = I0;
u(0,3) = Y0;
// initial conditions
for(i=0;i<counts;i++)
{
state_type x = { X0 , I0 , Y0 };
integrate( lorenz , x , t0 , t1 , error , write_lorenz );
}
return u; // the variable I hope will be global
}
Here is a simple adaptation of the pure C++ file you linked to. We simply define a struct of three vectors into which we push the elements of each iterations--as opposed to printing them to standard output.
For data structures that grow, we prefer C++ standard library types (as our types have to be like R types, their internals do not match well to increasing one-by-one which is expensive for them). So at the end, we just copy into an R data.frame.
#include <boost/array.hpp>
#include <boost/numeric/odeint.hpp>
#include <Rcpp.h>
// [[Rcpp::depends(BH)]]
// [[Rcpp::plugins(cpp11)]]
using namespace std;
using namespace boost::numeric::odeint;
const double sigma = 10.0, r = 28.0, b = 8.0 / 3.0;
typedef boost::array< double , 3 > state_type;
void lorenz( const state_type &x , state_type &dxdt , double t ) {
dxdt[0] = sigma * ( x[1] - x[0] );
dxdt[1] = r * x[0] - x[1] - x[0] * x[2];
dxdt[2] = -b * x[2] + x[0] * x[1];
}
struct foo { std::vector<double> a, b, c; };
struct foo f;
void append_lorenz(const state_type &x , const double t ) {
f.a.push_back(x[0]);
f.b.push_back(x[1]);
f.c.push_back(x[2]);
}
using namespace Rcpp;
// [[Rcpp::export]]
DataFrame callMain() {
state_type x = { 10.0 , 1.0 , 1.0 }; // initial conditions
integrate( lorenz , x , 0.0 , 25.0 , 0.1 , append_lorenz );
return DataFrame::create(Named("a") = f.a,
Named("b") = f.b,
Named("c") = f.c);
}
/*** R
res <- callMain()
print(head(res))
*/
Here is the output of the R code (intentially limited to fist few rows):
R> sourceCpp("/tmp/lorenz.cpp")
R> res <- callMain()
R> print(head(res))
a b c
1 10.00000 1.00000 1.00000
2 9.40816 2.99719 1.12779
3 8.92164 5.35684 1.46991
4 8.68193 7.82671 2.05762
5 8.73730 10.42718 2.94783
6 9.11080 13.10452 4.18849
R>