To describe the problem, I am trying to use objects in my code to stream line a three body problem. I have the following code for the object:
#include <stdlib.h>
#include <cstdio>
#include <iostream>
#include <cmath>
#include <vector>
#include "star.h"
using namespace std;
Star::Star( double m, double x_p, double y_p, double x_v, double y_v )
{
init( m, x_p, y_p, x_v, y_v);
}
void Star::init( double m, double x_p, double y_p, double x_v, double y_v )
{
Mass = m;
X_Position = x_p;
Y_Position = y_p;
X_Velocity = x_v;
Y_Velocity = y_v;
R_Position[0] = X_Position;
R_Position[1] = Y_Position;
R_Velocity[0] = X_Velocity;
R_Velocity[1] = Y_Velocity;
}
double Star::potential( Star star2, double dx, double dy )
{
double G = 3.0548e34;
double Potential;
double x_component = X_Position - star2.X_Position + dx;
double y_component = Y_Position - star2.Y_Position + dy;
double R = sqrt(x_component*x_component + y_component*y_component);
Potential = G* Mass* star2.Mass / R;
return Potential;
}
double * Star::compute_forces( Star star2 )
{
double h_x = ( X_Position - star2.X_Position )/1000;
double h_y = ( Y_Position - star2.Y_Position )/1000;
double *F = new double[2];
F[0] = ( potential( star2, h_x, 0.0 ) - potential( star2, -h_x, 0.0 ) )/2*h_x;
F[1] = ( potential( star2, 0.0, h_y ) - potential( star2, 0.0, -h_y ) )/2*h_y;
return F;
}
void Star::verlet( Star star2, double h )
{
double *Force = compute_forces( star2 );
X_Position += h*X_Velocity + 0.5*h*h*Force[ 0 ];
Y_Position += h*Y_Velocity + 0.5*h*h*Force[ 1 ];
double *Force_new = compute_forces( star2 );
X_Velocity += 0.5*h*(Force[ 0 ] + Force_new[ 0 ] );
Y_Velocity += 0.5*h*(Force[ 1 ] + Force_new[ 1 ] );
}
Now I believe that the velocity verlet algorithm is correct, but when I run the code using this main file:
#include <iostream>
#include <fstream>
#include <cmath>
#include <cstdio>
#include "star.h"
using namespace std;
int main()
{
Star star1( 50, 0.0, 0.0, 0.0, 0.0 );
Star star2( 1.00, 0.0, 1.0, -1.0, 1.0 );
Star star3( 1.00, 0.0, -1.0, 1.0, 1.0 );
Star arr[3] = { star1, star2, star3 };
double h = 10/1000;
//for ( double time = 0.0; time <= 10.0; )
//{
for ( int inst = 0 ; inst< 3; ++inst )
{
for ( int jnst = 0; jnst < 3; ++jnst )
{
if ( inst != jnst )
{
arr[ inst ].verlet( arr[ jnst ], h );
double *pos = arr[ inst ].get_positions();
cout << " " << pos[ 0 ] << " " << pos[ 1 ] << endl;
}
}
}
//time += h;
//}
return 0;
}
The values of members of the Star object are not updating :/. Is there something I am missing?
the out put of the cout is this:
0 0
0 0
0 1
0 1
0 -1
0 -1
Thank you in advance!
Edit:
I tried implementing a std::vector<double> for my forces, but I ended up with a segmentation fault.
Edit 2:
After checking my get_positions() method I noticed it was returning only the initialized values. So I tried implementing this:
std::vector<double> get_positions(){ std::vector<double> temp = { X_Position , Y_Position }; return temp; }
And it worked so i implemented the following into my main code.
std::vector<double> p1 = star1.get_positions();
std::vector<double> p2 = star2.get_positions();
std::vector<double> p3 = star3.get_positions();
cout << p1[ 0 ] << " " << p1[ 1 ] << " " << p2[ 0 ] << " " << p2[ 1 ] << " " << p3[ 0 ] << " " << p3[ 1 ] << endl;
However now I am stuck on a completely new problem... Now I am getting the following numbers for the algorithm updates!
5.66002e-320 2.31834e-316
1.132e-316 4.63669e-313
1.698e-319 6.95503e-316
1.132e-316 4.63669e-313
5.66002e-320 2.31834e-316
1.132e-316 4.63669e-313
1.698e-319 6.95503e-316
1.132e-316 4.63669e-313
5.66002e-320 2.31834e-316
1.132e-316 4.63669e-313
1.698e-319 6.95503e-316
1.132e-316 4.63669e-313
Which means some where I am multiplying by zeros somewhere in my code. The problem is I cant for the life of me see where. Thanks if there is any help!
Error
If you want to divide by 2*h_x, you need to write this as /(2*h_x), else you divide by 2 and multiply by h_x, giving miniscule values for forces and thus not moving the system by much.
To complement this, you defined the step size in the main program as
double h = 10/1000;
The value on the right is identified as result of an integer division, which is 0. With this step size nothing will change.
Style
Do not construct two data fields for the same value, you would have to ensure that these fields are always synchronized. Use getter methods to present data in a different format.
For science it would be better to use an established vector class that then also provides vector arithmetic, like the one of boost/Eigen.
Use initialization list syntax in the constructor, you do not need an init function to just assign the values.
Verlet
The Verlet method does not work this way. Even if everything goes right coding-wise, the result is a first order method that neither preserves energy nor momentum.
For using Verlet with gravity simulations, see N-Body Gravity Simulation in JavaScript.
The same in a slightly different context, Lennard-Jones potential simulation.
Perhaps also this discussion about general properties of the Verlet method, Velocity verlet algorithm not conserving energy, can be helpful.
The short version is, the stages of the Verlet method are the outer frame. In each stage, all computations have to be carried out for all objects before changing to the next stage. That is, all velocities change, then all positions chance, then all forces are computed and accumulated, then all velocities change with the new forces/accelerations for all objects.
Mixing these steps destroys the order of the method and all conservation properties. (The first two stages can be interleaved, as there is no interaction between objects.)
I implemented some of the suggested changes, using the data of the Pleiades IVP test suite example, as the provided data lead to a rapid explosion of the system.
The main program solarsystem.c with the main Verlet loop
#include <iostream>
#include <cstdio>
#include <vector>
#include "star.h"
using namespace std;
int main()
{
vector<Star> arr = {
Star( 1, 3.0, 3.0, 0.0, 0.0 ),
Star( 2, 3.0,-3.0, 0.0, 0.0 ),
Star( 3,-1.0, 2.0, 0.0, 0.0 ),
Star( 4,-3.0, 0.0, 0.0,-1.25 ),
Star( 5, 2.0, 0.0, 0.0, 1.0 ),
Star( 6,-2.0,-4.0, 1.75, 0.0 ),
Star( 7, 2.0, 4.0,-1.5, 0.0 )
};
int N = arr.size();
double dt = 0.001;
int count = 10;
for ( double time = 0.0; time <= 3.0; time += dt)
{
for ( int inst = 0 ; inst< N; ++inst ) {
arr[inst].Verlet_stage1(dt);
}
for ( int inst = 0 ; inst< N; ++inst ) {
for ( int jnst = inst+1; jnst < N; ++jnst ) {
arr[inst].acceleration(arr[jnst]);
}
}
for ( int inst = 0 ; inst< N; ++inst ) {
arr[inst].Verlet_stage2(dt);
}
if( 10 == count) {
count = 0;
for ( int inst = 0 ; inst< N; ++inst ) {
cout << " " << arr[inst].Position[1] << " " << arr[inst].Position[0];
}
cout << "\n";
}
count++;
}
return 0;
}
and the implementation of the Star class with header
#pragma once
#include <eigen3/Eigen/Dense>
typedef Eigen::Vector2d Vec2D;
const double G = 1;
class Star {
public:
Star( double m, double x_p, double y_p, double x_v, double y_v )
:Mass(m),Position(x_p,y_p),Velocity(x_v,y_v) {};
double Mass;
Vec2D Position, Velocity, Acceleration;
void Verlet_stage1(double dt);
void Verlet_stage2(double dt);
double potential(Star other);
void acceleration(Star &other);
};
and corpus
#include "star.h"
double Star::potential( Star other )
{
Vec2D diff = Position-other.Position;
double R = diff.norm();
return G * Mass * other.Mass / R;
}
void Star::acceleration( Star &other )
{
Vec2D diff = Position-other.Position;
double R = diff.norm();
Vec2D acc = (-G / (R*R*R)) * diff;
Acceleration += other.Mass * acc;
other.Acceleration -= Mass * acc;
}
void Star::Verlet_stage1( double dt )
{
Velocity += (0.5*dt) * Acceleration;
Position += dt*Velocity;
Acceleration *= 0;
}
void Star::Verlet_stage2( double dt )
{
Velocity += (0.5*dt) * Acceleration;
}
This results in the trajectories below. The picture is very depending on the step size dt as near singularities of the potential function, that is, if bodies come very close together, the promise of symplectic methods of near conservation of energy and momentums breaks apart.
I'm personally not against using raw pointers, but complications occur when they don't get managed properly. I have no idea what this code does, more so how it does! Nevertheless, I have tried ameliorating a few errors which I could observe, but evidently this code requires a serious overhaul. I suppose the shortcomings in this code are just due to inexperience, which can be understood.
https://gcc.godbolt.org/z/5zT5o9 Please do keep in mind that this code is still leaking due to usage(non-manage) of raw pointers in various function bodies.
Related
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.
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.
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.
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>
I met a very strange thing, two days ago I try to debug the code.
I'm running the code on a Windows 7 64bit OS. In the main I calculate a mathematical model by knowing the input signal, which will be applied in the control algorithm SOOP. The calculation is ok in the main, but in the soop function while doing the same thing i have close but not identical results. Why?
I tired with float too and I got the same result.
Does double get rounded if I calculate in a function not in the main?
Main:
#include <unistd.h>
#include <iostream>
#include <windows.h>
#include <fstream>
#include <math.h>
#include "model.h"
#include "SOOP.h"
using namespace std;
int main( void )
{
ofstream myfile;
myfile.open ("modelTest.txt");
stateE current_state; // = new stateE;
initstateE(current_state);
current_state.variables[0] = 0.0;
current_state.variables[0] = -3.0*PI/2.0;
cout << "program init" << endl;
// ==============Model testing
myfile << current_state.variables[0] <<", "<< current_state.variables[2] <<", "<<current_state.reward << ", "<< fmod((current_state.variables[0])+ PI, 2.0 * PI) -PI <<endl;
double utmp = -10.0;
for (int i=0;i<3;i++)
{
current_state.variables[0] = -3.0*PI/2.0;
copyStateE(current_state, nextstateE(current_state, utmp));
utmp = utmp+10.0;
myfile << current_state.variables[0] <<", "<< current_state.variables[2] <<", "<<current_state.reward << ", "<< fmod((current_state.variables[0])+ PI, 2.0 * PI) -PI <<endl;
}
// ==============SOOP testing
initstateE(current_state);
current_state.variables[0] = -3.0*PI/2.0;
double commnadSignal[initlen];
for(int i=0; i<1; i++)
{
memcpy(commnadSignal,soop(current_state),sizeof(double)*initlen);
copyStateE(current_state,nextstateE(current_state, commnadSignal[0]));
}
myfile.close();
return 0;
}
The model library:
stateE nextstateE(stateE s, double votlageSignal) {
std::cout<< "in nextstateE"<< std::endl;
stateE newstateE;// = (stateE*)malloc(sizeof(stateE));
memcpy(newstateE.variables, s.variables, sizeof(double) * nbHiddenstateEVariables);
newstateE.isTerminal = s.isTerminal;
std::cout << " v "<< votlageSignal << " l "<< s.variables[0] << std::endl;
double Vm = votlageSignal;
double lambda = s.variables[0];
double dLambda = s.variables[1];
double theta = s.variables[2];
double dTheta = s.variables[3];
double thetaNext = theta + timeStep*dTheta;
double dThetaNext = dTheta + timeStep*( (1/(aP*cP-pow(bP,2)*pow(cos(lambda),2))) *(-bP*cP*sin(lambda)*pow(dLambda,2)+bP*dP*sin(lambda)*cos(lambda)-cP*eP*dTheta+cP*fP*Vm) );
double lambdaNext = lambda + timeStep*dLambda;
double dLambdaNext = dLambda + timeStep*( (1/(aP*cP-pow(bP,2)*pow(cos(lambda),2))) *(aP*dP*sin(lambda)-pow(bP,2)*sin(lambda)*cos(lambda)*pow(dLambda,2)-bP*eP*cos(lambda)*dTheta+bP*fP*cos(lambda)*Vm) );
//========== Normalization of lambda and theta
if (lambdaNext>0)
lambdaNext = fmod(lambdaNext+PI, 2.0*PI)-PI;
else
lambdaNext = fmod(lambdaNext-PI, 2.0*PI)+PI;
if (thetaNext>0)
thetaNext = fmod(thetaNext+PI, 2.0*PI)-PI;
else
thetaNext = fmod(thetaNext-PI, 2.0*PI)+PI;
newstateE.variables[0] = lambdaNext;
newstateE.variables[1] = dLambdaNext;
newstateE.variables[2] = thetaNext;
newstateE.variables[3] = dThetaNext;
double newReward;
if(s.isTerminal) {
newReward = 0.0;
} else {
newReward = 1 - (pow(lambdaNext,2.0)*qReward + pow(votlageSignal,2.0)*rReward)/(pow(PI,2.0)*qReward+ pow(maxVoltage,2.0)*rReward);
}
newstateE.reward=newReward;
return newstateE;
}
void copyStateE(stateE& destination, stateE original)
{
initstateE(destination);
destination.variables[0] = original.variables[0]; // lambda
destination.variables[1] = original.variables[1]; // dLambda
destination.variables[2] = original.variables[2]; // theta
destination.variables[3] = original.variables[3]; // dTheta
destination.isTerminal = 0;
destination.reward = original.reward;
}
The controller library uses the model library:
double * soop(stateE& s0)
{
ofstream myfile;
myfile.open ("soopTest.txt");
bool stopFlag = false;
unsigned int counter = 0;
unsigned int currentBudget = 0;
unsigned int listLenght = 0;
unsigned int maxLengthSequence = 0;
double tmpU = -10.0;
for (int i=0;i<3;i++)
{
double sPtmp[initlen] = {0};
unsigned int stmp[initlen] = {0};
stateE newstateE[initlen];
stateE tmpE;
sPtmp[0] = ((double)i)/3.0;
stmp[0] = 1;
initstateE(tmpE);
tmpE.variables[0]=-3.0*PI/2.0;
copyStateE(tmpE, nextstateE(tmpE , tmpU ));
tmpU = tmpU + 10.0;
newstateE[0] = nextstateE(s0, unnormU(middleOfBox((double)i/3.0, stmp[0])) );
myfile << "U norm "<< middleOfBox((double)i/3.0, stmp[0])<< " Unorm "<<unnormU(middleOfBox((double)i/3.0, stmp[0])) << endl;
myfile <<"alp " << tmpE.variables[0] << " th " << tmpE.variables[2] << " R " << tmpE.reward << endl;
myfile <<"alp " << newstateE[0].variables[0] << " th " << newstateE[0].variables[2] << " R " << newstateE[0] .reward << endl;
myfile << endl;
}
myfile.close();
}
The two text files modelTest.txt and soop Test.txt should show the same results, cuz I applay the same input parameters (s0 and [-10,0,10]) in the main and in the soop function. But I get different rusults in the text files.
soop Test file:
U norm 0.166667 Unorm -10
alp 1.5708 th 0 R 0.75
alp 1.5708 th 0 R 0.75
U norm 0.5 Unorm 0
alp 1.5708 th 0 R 0.75
alp 1.5708 th 0 R 0.75
U norm 0.833333 Unorm 10
alp 1.5708 th 0 R 0.75
alp 1.5708 th 0 R 0.75
modelTest file:
alp 1.5708, th 0, R 0.75 (for s0 and -10)
alp 1.57084, th -0.000115852, R 0.749986 (for s0 and 0)
alp 1.57088, th -0.000230942, R 0.749972 (for s0 and 10)
My mistake, in the main I didn't initialized all the states of current_state (only one angle). initStateE(current_state) is missing in the main loop.
Next mistake, that the reward factor for voltageSignal, 'rReward = 0' so the Reward wont change in function of the control value.
The biggest mistake is to suppose that the systems angular state parameter would change after the first simulation. I'm using Euler discrezitation for f(Q(t),U(t)) - a 2nd order differential equation, so a control signal has effect only on first derivative in the first iteration and on the position it has effect after the 2nd iteration.
P_{k+1} = P_k + daltaT * Q_k
Q_{k+1} = Q_k + deltaT * f(Q_k, U_k)
where deltaT is the sampling time.