OpenFPM  5.2.0
Project that contain the implementation of distributed structures
rk4-odeint.cpp
1 
2 #include <stddef.h>
3 #include "Vector/vector_dist.hpp"
4 #include <iostream>
5 #include <fstream>
6 #include "Operators/Vector/vector_dist_operators.hpp"
7 #include "Vector/vector_dist_subset.hpp"
8 #include "Decomposition/Distribution/SpaceDistribution.hpp"
9 #include "OdeIntegrators/OdeIntegrators.hpp"
10 #include <vector>
11 #include <numeric>
12 
13 double t=-5.0, tf=5.0, dt = 0.01;
14 
15 
16 void Exponential2( const state_type_1d_ofp &x , state_type_1d_ofp &dxdt , const double t )
17 {
18  dxdt.data.get<0>() = x.data.get<0>();
19 }
20 
21 void sigmoid2( const state_type_1d_ofp &x , state_type_1d_ofp &dxdt , const double t )
22 {
23  // g'(t) = g(t) * (1-sigma)
24  dxdt.data.get<0>() = x.data.get<0>() * (1- (1/(1+exp(-t))) );
25 }
26 
27 
28 template <typename stepper_type>
29 void run_stepper_const(vector_dist<2, double, aggregate<double, double,double>> &Particles,
30  void (*derivative)(const state_type_1d_ofp &, state_type_1d_ofp &, const double),
31  std::vector<double> &runtime_v,std::vector<double> &norm_inf_v, std::vector<double> &norm_l2_v) {
32 
33  auto Init = getV<0>(Particles);
34  auto Sol = getV<1>(Particles);
35  auto OdeSol = getV<2>(Particles);
36 
38  x0.data.get<0>() = Init;
39 
40  timer timer_integrate;
41  timer_integrate.start();
42  boost::numeric::odeint::integrate_const(stepper_type(), derivative, x0, t, tf, dt);
43  timer_integrate.stop();
44 
45 
46  OdeSol = x0.data.get<0>();
47 
48  double norm_inf = 0.0;
49  double norm_l2 = 0.0;
50 
51  auto it2 = Particles.getDomainIterator();
52  while (it2.isNext()) {
53  auto p = it2.get();
54  // calculate error
55  double diff = Particles.getProp<1>(p) - Particles.getProp<2>(p);
56  // calculate infinity norm
57  if (fabs(diff) > norm_inf) {
58  norm_inf = fabs(diff);
59  }
60  // calculate L2 norm
61  norm_l2 += diff * diff;
62  ++it2;
63  }
64  norm_l2 = sqrt(norm_l2);
65  double rt=timer_integrate.getwct();
66  auto &v_cl=create_vcluster();
67  v_cl.sum(rt);
68  v_cl.execute();
69 
70  runtime_v.push_back(rt);
71  norm_inf_v.push_back(norm_inf);
72  norm_l2_v.push_back(norm_l2);
73 
74  //std::cout << "Runtime: " << rt/v_cl.size() << std::endl;
75  //std::cout << "Inf: " << norm_inf << std::endl;
76  //std::cout << "L2: " << norm_l2 << std::endl;
77 
78 }
79 
80 template <typename stepper_type>
81 void run_stepper_adaptive(vector_dist<2, double, aggregate<double, double,double>> &Particles,
82  void (*derivative)(const state_type_1d_ofp &, state_type_1d_ofp &, const double),
83  std::vector<double> &runtime_v,std::vector<double> &norm_inf_v, std::vector<double> &norm_l2_v) {
84 
85  auto Init = getV<0>(Particles);
86  auto Sol = getV<1>(Particles);
87  auto OdeSol = getV<2>(Particles);
88 
90  x0.data.get<0>() = Init;
91 
92  timer timer_integrate;
93  timer_integrate.start();
94  boost::numeric::odeint::integrate_adaptive( stepper_type() , derivative , x0 , t , tf , dt);
95  timer_integrate.stop();
96 
97 
98  OdeSol = x0.data.get<0>();
99 
100  double norm_inf = 0.0;
101  double norm_l2 = 0.0;
102 
103  auto it2 = Particles.getDomainIterator();
104  while (it2.isNext()) {
105  auto p = it2.get();
106  // calculate error
107  double diff = Particles.getProp<1>(p) - Particles.getProp<2>(p);
108  // calculate infinity norm
109  if (fabs(diff) > norm_inf) {
110  norm_inf = fabs(diff);
111  }
112  // calculate L2 norm
113  norm_l2 += diff * diff;
114  ++it2;
115  }
116  norm_l2 = sqrt(norm_l2);
117 
118  double rt=timer_integrate.getwct();
119  auto &v_cl=create_vcluster();
120  v_cl.sum(rt);
121  v_cl.execute();
122 
123  runtime_v.push_back(rt);
124  norm_inf_v.push_back(norm_inf);
125  norm_l2_v.push_back(norm_l2);
126 
127  //std::cout << "Runtime: " << rt/v_cl.size() << std::endl;
128  //std::cout << "Inf: " << norm_inf << std::endl;
129  //std::cout << "L2: " << norm_l2 << std::endl;
130 
131 }
132 
133 double average(std::vector<double> &nums) {
134  return std::accumulate(nums.begin(), nums.end(), 0.0) / static_cast<double>(nums.size());
135 }
136 
137 int main(int argc, char* argv[])
138 {
139 
140  // initialize the library
141  openfpm_init(&argc,&argv);
142 
143  // std::cout << "odeint"<< std::endl;
144 
145 
146  // output
147  std::vector<double> runtime_rk4_const;
148  std::vector<double> runtime_rk5_const;
149  std::vector<double> runtime_rk78_const;
150  std::vector<double> runtime_rk5_adapt;
151 
152  std::vector<double> norm_inf_rk4_const;
153  std::vector<double> norm_inf_rk5_const;
154  std::vector<double> norm_inf_rk78_const;
155  std::vector<double> norm_inf_rk5_adapt;
156 
157  std::vector<double> norm_l2_rk4_const;
158  std::vector<double> norm_l2_rk5_const;
159  std::vector<double> norm_l2_rk78_const;
160  std::vector<double> norm_l2_rk5_adapt;
161 
162  size_t edgeSemiSize = std::stof(argv[1]);
163  const size_t sz[2] = {edgeSemiSize,edgeSemiSize };
164  Box<2, double> box({ 0, 0 }, { 1.0, 1.0 });
165  size_t bc[2] = { NON_PERIODIC, NON_PERIODIC };
166  double spacing[2];
167  spacing[0] = 1.0 / (sz[0] - 1);
168  spacing[1] = 1.0 / (sz[1] - 1);
169  double rCut = 3.9 * spacing[0];
170  Ghost<2, double> ghost(rCut);
171 
172  vector_dist<2, double, aggregate<double, double,double>> Particles(0, box, bc, ghost);
173 
174  // analytical solution
175  auto it = Particles.getGridIterator(sz);
176  while (it.isNext()) {
177  Particles.add();
178  auto key = it.get();
179  mem_id k0 = key.get(0);
180  double xp0 = k0 * spacing[0];
181  Particles.getLastPos()[0] = xp0;
182  mem_id k1 = key.get(1);
183  double yp0 = k1 * spacing[1];
184  Particles.getLastPos()[1] = yp0;
185 
186  // Particles.getLastProp<0>() = xp0*yp0*1/(1+exp(-t));
187  // Particles.getLastProp<1>() = xp0*yp0*1/(1+exp(-tf));
188 
189  Particles.getLastProp<0>() = xp0 * yp0 * exp(t);
190  Particles.getLastProp<1>() = xp0 * yp0 * exp(tf);
191 
192  ++it;
193  }
194 
195  auto Init = getV<0>(Particles);
196  auto Sol = getV<1>(Particles);
197  auto OdeSol = getV<2>(Particles);
198 
200 
201  typedef boost::numeric::odeint::runge_kutta4<state_type_1d_ofp, double, state_type_1d_ofp, double, boost::numeric::odeint::vector_space_algebra_ofp> rk4_stepper_type;
202  typedef boost::numeric::odeint::runge_kutta_dopri5<state_type_1d_ofp, double, state_type_1d_ofp, double, boost::numeric::odeint::vector_space_algebra_ofp> dopri5_stepper_type;
203  typedef boost::numeric::odeint::runge_kutta_fehlberg78<state_type_1d_ofp, double, state_type_1d_ofp, double, boost::numeric::odeint::vector_space_algebra_ofp> fehlberg78_stepper_type;
204 
205 // void (*derivative)(const state_type_1d_ofp &, state_type_1d_ofp &, const double);
206 // derivative = &Exponential2;
207 
208  for (int i = 0; i < 3; ++i) {
209 
210  run_stepper_const<rk4_stepper_type>(Particles, &Exponential2, runtime_rk4_const, norm_inf_rk4_const, norm_l2_rk4_const);
211  run_stepper_const<dopri5_stepper_type>(Particles, &Exponential2, runtime_rk5_const, norm_inf_rk5_const, norm_l2_rk5_const);
212  run_stepper_const<fehlberg78_stepper_type>(Particles, &Exponential2, runtime_rk78_const, norm_inf_rk78_const, norm_l2_rk78_const);
213  run_stepper_adaptive<dopri5_stepper_type>(Particles, &Exponential2, runtime_rk5_adapt, norm_inf_rk5_adapt, norm_l2_rk5_adapt);
214 
215  }
216 
217  auto & vcl = create_vcluster();
218 
219  if (vcl.getProcessUnitID() == 0) {
220 
221 
222  std::ofstream output_runtime;
223  std::ofstream output_inf_norm;
224  std::ofstream output_l2_norm;
225 
226 
227  // head line
228  std::string headline = "cores,rk4,dopri5,fehlberg78,dopri5 adaptive";
229  if (access( "runtime.csv", F_OK ) == -1) {
230  output_runtime.open("runtime.csv");
231  output_runtime << headline << "\n";
232  }
233  else {
234  output_runtime.open("runtime.csv",std::ios::app);
235  }
236 
237  if (access( "inf_norm.csv", F_OK ) == -1) {
238  output_inf_norm.open("inf_norm.csv");
239  output_inf_norm << headline << "\n";
240  }
241  else {
242  output_inf_norm.open("inf_norm.csv",std::ios::app);
243  }
244 
245  if (access( "l2_norm.csv", F_OK ) == -1) {
246  output_l2_norm.open("l2_norm.csv");
247  output_l2_norm << headline << "\n";
248  }
249  else {
250  output_l2_norm.open("l2_norm.csv",std::ios::app);
251  }
252 
253  output_runtime << vcl.getProcessingUnits()
254  << "," << average(runtime_rk4_const)
255  << "," << average(runtime_rk5_const)
256  << "," << average(runtime_rk78_const)
257  << "," << average(runtime_rk5_adapt)
258  << "\n";
259 
260  output_inf_norm << vcl.getProcessingUnits()
261  << "," << average(norm_inf_rk4_const)
262  << "," << average(norm_inf_rk5_const)
263  << "," << average(norm_inf_rk78_const)
264  << "," << average(norm_inf_rk5_adapt)
265  << "\n";
266 
267  output_l2_norm << vcl.getProcessingUnits()
268  << "," << average(norm_l2_rk4_const)
269  << "," << average(norm_l2_rk5_const)
270  << "," << average(norm_l2_rk78_const)
271  << "," << average(norm_l2_rk5_adapt)
272  << "\n";
273 
274 
275 
276 // output_l2_norm << vcl.getProcessingUnits() << "," << "rk4" << "," << std::accumulate(norm_l2_results.begin(), norm_l2_results.end(), 0.0) / static_cast<double>(norm_l2_results.size()) << "\n";
277 
278 
279  }
280 
281 
282  openfpm_finalize();
283 
284 }
This class represent an N-dimensional box.
Definition: Box.hpp:60
Definition: Ghost.hpp:40
Class for cpu time benchmarking.
Definition: timer.hpp:28
void stop()
Stop the timer.
Definition: timer.hpp:119
void start()
Start the timer.
Definition: timer.hpp:90
double getwct()
Return the elapsed real time.
Definition: timer.hpp:130
Distributed vector.
aggregate of properties, from a list of object if create a struct that follow the OPENFPM native stru...
Definition: aggregate.hpp:221
A 1d Odeint and Openfpm compatible structure.