OpenFPM_pdata  4.1.0
Project that contain the implementation of distributed structures
main_cpu_best.cpp
1 #include "Vector/vector_dist.hpp"
2 #include "Decomposition/CartDecomposition.hpp"
3 #include "data_type/aggregate.hpp"
4 #include "Plot/GoogleChart.hpp"
5 #include "Plot/util.hpp"
6 #include "timer.hpp"
7 
8 #ifdef TEST_RUN
9 size_t nstep = 100;
10 #else
11 size_t nstep = 1000;
12 #endif
13 
14 typedef float real_number;
15 
16 constexpr int velocity = 0;
17 constexpr int force = 1;
18 
19 
20 template<typename VerletList>
21 void calc_forces(vector_dist<3,real_number, aggregate<real_number[3],real_number[3]> > & vd, VerletList & NN, real_number sigma12, real_number sigma6, real_number r_cut)
22 {
23  // Reset force on the ghost
24 
25  auto itg = vd.getDomainAndGhostIterator();
26 
27  while (itg.isNext())
28  {
29  auto p = itg.get();
30 
31  // Reset force
32  vd.getProp<force>(p)[0] = 0.0;
33  vd.getProp<force>(p)[1] = 0.0;
34  vd.getProp<force>(p)[2] = 0.0;
35 
36  ++itg;
37  }
38 
40 
41  // Get an iterator over particles
42  auto it2 = vd.getParticleIteratorCRS(NN);
43 
45 
46  // For each particle p ...
47  while (it2.isNext())
48  {
49  // ... get the particle p
50  auto p = it2.get();
51 
52  // Get the position xp of the particle
53  Point<3,real_number> xp = vd.getPos(p);
54 
55  // Get an iterator over the neighborhood particles of p
56  // Note that in case of symmetric
57  auto Np = NN.template getNNIterator<NO_CHECK>(p);
58 
59  // For each neighborhood particle ...
60  while (Np.isNext())
61  {
62  // ... q
63  auto q = Np.get();
64 
65  // if (p == q) skip this particle
66  if (q == p) {++Np; continue;};
67 
68  // Get the position of q
69  Point<3,real_number> xq = vd.getPos(q);
70 
71  // Get the distance between p and q
72  Point<3,real_number> r = xp - xq;
73 
74  // take the norm of this vector
75  real_number rn = norm2(r);
76 
77  if (rn > r_cut * r_cut) {++Np;continue;}
78 
79  // Calculate the force, using pow is slower
80  Point<3,real_number> f = 24.0*(2.0 *sigma12 / (rn*rn*rn*rn*rn*rn*rn) - sigma6 / (rn*rn*rn*rn)) * r;
81 
82  // we sum the force produced by q on p
83  vd.template getProp<force>(p)[0] += f.get(0);
84  vd.template getProp<force>(p)[1] += f.get(1);
85  vd.template getProp<force>(p)[2] += f.get(2);
86 
88 
89  // we sum the force produced by p on q
90  vd.template getProp<force>(q)[0] -= f.get(0);
91  vd.template getProp<force>(q)[1] -= f.get(1);
92  vd.template getProp<force>(q)[2] -= f.get(2);
93 
95 
96  // Next neighborhood
97  ++Np;
98  }
99 
100  // Next particle
101  ++it2;
102  }
103 
104  // Sum the contribution to the real particles
105  vd.ghost_put<add_,force>();
106 }
107 
108 
109 template<typename VerletList>
110 real_number calc_energy(vector_dist<3,real_number, aggregate<real_number[3],real_number[3]> > & vd, VerletList & NN, real_number sigma12, real_number sigma6, real_number r_cut)
111 {
112  real_number E = 0.0;
113 
114  real_number rc = r_cut*r_cut;
115  real_number shift = 4.0 * ( sigma12 / (rc*rc*rc*rc*rc*rc) - sigma6 / ( rc*rc*rc) );
116 
117  // Get an iterator over particles
118  auto it2 = vd.getParticleIteratorCRS(NN);
119 
120  // For each particle ...
121  while (it2.isNext())
122  {
123  // ... p
124  auto p = it2.get();
125 
126  // Get the position of the particle p
127  Point<3,real_number> xp = vd.getPos(p);
128 
129  // Get an iterator over the neighborhood particles of p
130  auto Np = NN.template getNNIterator<NO_CHECK>(p);
131 
132  real_number Ep = E;
133 
134  // For each neighborhood of the particle p
135  while (Np.isNext())
136  {
137  // Neighborhood particle q
138  auto q = Np.get();
139 
140  // if p == q skip this particle
141  if (q == p) {++Np; continue;};
142 
143  // Get position of the particle q
144  Point<3,real_number> xq = vd.getPos(q);
145 
146  // take the normalized direction
147  real_number rn = norm2(xp - xq);
148 
149  if (rn >= r_cut*r_cut) {++Np;continue;}
150 
151  // potential energy (using pow is slower)
152  E += 4.0 * ( sigma12 / (rn*rn*rn*rn*rn*rn) - sigma6 / ( rn*rn*rn) ) - shift;
153 
154  // Next neighborhood
155  ++Np;
156  }
157 
158  // To note that the crossing scheme go across the domain particles +
159  // some ghost particles. This mean that we have to filter out the ghost
160  // particles otherwise we count real_number energies
161  //
162  if (p < vd.size_local())
163  {
164  // Kinetic energy of the particle given by its actual speed
165  E += (vd.template getProp<velocity>(p)[0]*vd.template getProp<velocity>(p)[0] +
166  vd.template getProp<velocity>(p)[1]*vd.template getProp<velocity>(p)[1] +
167  vd.template getProp<velocity>(p)[2]*vd.template getProp<velocity>(p)[2]) / 2;
168  }
169 
170  // Next Particle
171  ++it2;
172  }
173 
174  // Calculated energy
175  return E;
176 }
177 
178 int main(int argc, char* argv[])
179 {
180  real_number dt = 0.00005;
181  real_number sigma = 0.01;
182  real_number r_cut = 3.0*sigma;
183  real_number r_gskin = 1.3*r_cut;
184  real_number sigma12 = pow(sigma,12);
185  real_number sigma6 = pow(sigma,6);
186 
189 
190  openfpm_init(&argc,&argv);
191  Vcluster<> & v_cl = create_vcluster();
192 
193  // we will use it do place particles on a 10x10x10 Grid like
194  size_t sz[3] = {100,100,100};
195 
196  // domain
197  Box<3,float> box({0.0,0.0,0.0},{1.0,1.0,1.0});
198 
199  // Boundary conditions
200  size_t bc[3]={PERIODIC,PERIODIC,PERIODIC};
201 
202  // ghost, big enough to contain the interaction radius
203  Ghost<3,float> ghost(r_gskin);
204  ghost.setLow(0,0.0);
205  ghost.setLow(1,0.0);
206  ghost.setLow(2,0.0);
207 
208  vector_dist<3,real_number, aggregate<real_number[3],real_number[3]> > vd(0,box,bc,ghost,BIND_DEC_TO_GHOST);
209 
210  size_t k = 0;
211  size_t start = vd.accum();
212 
213  auto it = vd.getGridIterator(sz);
214 
215  while (it.isNext())
216  {
217  vd.add();
218 
219  auto key = it.get();
220 
221  vd.getLastPos()[0] = key.get(0) * it.getSpacing(0);
222  vd.getLastPos()[1] = key.get(1) * it.getSpacing(1);
223  vd.getLastPos()[2] = key.get(2) * it.getSpacing(2);
224 
225  vd.template getLastProp<velocity>()[0] = 0.0;
226  vd.template getLastProp<velocity>()[1] = 0.0;
227  vd.template getLastProp<velocity>()[2] = 0.0;
228 
229  vd.template getLastProp<force>()[0] = 0.0;
230  vd.template getLastProp<force>()[1] = 0.0;
231  vd.template getLastProp<force>()[2] = 0.0;
232 
233  k++;
234  ++it;
235  }
236 
237  vd.map();
238  vd.ghost_get<>();
239 
240  timer tsim;
241  tsim.start();
242 
243  // Get the Cell list structure
244  auto NN = vd.getVerletCrs(r_gskin);;
245 
246  // calculate forces
247  calc_forces(vd,NN,sigma12,sigma6,r_cut);
248  unsigned long int f = 0;
249 
250  int cnt = 0;
251  real_number max_disp = 0.0;
252 
253  // MD time stepping
254  for (size_t i = 0; i < nstep ; i++)
255  {
256  // Get the iterator
257  auto it3 = vd.getDomainIterator();
258 
259  real_number max_displ = 0.0;
260 
261  // integrate velicity and space based on the calculated forces (Step1)
262  while (it3.isNext())
263  {
264  auto p = it3.get();
265 
266  // here we calculate v(tn + 0.5)
267  vd.template getProp<velocity>(p)[0] += 0.5*dt*vd.template getProp<force>(p)[0];
268  vd.template getProp<velocity>(p)[1] += 0.5*dt*vd.template getProp<force>(p)[1];
269  vd.template getProp<velocity>(p)[2] += 0.5*dt*vd.template getProp<force>(p)[2];
270 
271  Point<3,real_number> disp({vd.template getProp<velocity>(p)[0]*dt,vd.template getProp<velocity>(p)[1]*dt,vd.template getProp<velocity>(p)[2]*dt});
272 
273  // here we calculate x(tn + 1)
274  vd.getPos(p)[0] += disp.get(0);
275  vd.getPos(p)[1] += disp.get(1);
276  vd.getPos(p)[2] += disp.get(2);
277 
278  if (disp.norm() > max_displ)
279  max_displ = disp.norm();
280 
281  ++it3;
282  }
283 
284  if (max_disp < max_displ)
285  max_disp = max_displ;
286 
287  // Because we moved the particles in space we have to map them and re-sync the ghost
288  if (cnt % 10 == 0)
289  {
290  vd.map();
291  vd.template ghost_get<>();
292  // Get the Cell list structure
293  vd.updateVerlet(NN,r_gskin,VL_CRS_SYMMETRIC);
294  }
295  else
296  {
297  vd.template ghost_get<>(SKIP_LABELLING);
298  }
299 
300  cnt++;
301 
302  // calculate forces or a(tn + 1) Step 2
303  calc_forces(vd,NN,sigma12,sigma6,r_cut);
304 
305  // Integrate the velocity Step 3
306  auto it4 = vd.getDomainIterator();
307 
308  while (it4.isNext())
309  {
310  auto p = it4.get();
311 
312  // here we calculate v(tn + 1)
313  vd.template getProp<velocity>(p)[0] += 0.5*dt*vd.template getProp<force>(p)[0];
314  vd.template getProp<velocity>(p)[1] += 0.5*dt*vd.template getProp<force>(p)[1];
315  vd.template getProp<velocity>(p)[2] += 0.5*dt*vd.template getProp<force>(p)[2];
316 
317  ++it4;
318  }
319 
320  // After every iteration collect some statistic about the confoguration
321  if (i % 100 == 0)
322  {
323  // We write the particle position for visualization (Without ghost)
324  vd.deleteGhost();
325  vd.write("particles_",f);
326 
327  // we resync the ghost
328  vd.ghost_get<>();
329 
330 
331  // We calculate the energy
332  real_number energy = calc_energy(vd,NN,sigma12,sigma6,r_cut);
333  auto & vcl = create_vcluster();
334  vcl.sum(energy);
335  vcl.max(max_disp);
336  vcl.execute();
337 
338  // we save the energy calculated at time step i c contain the time-step y contain the energy
339  x.add(i);
340  y.add({energy});
341 
342  // We also print on terminal the value of the energy
343  // only one processor (master) write on terminal
344  if (vcl.getProcessUnitID() == 0)
345  std::cout << "Energy: " << energy << " " << max_disp << " " << std::endl;
346 
347  max_disp = 0.0;
348 
349  f++;
350  }
351  }
352 
353  tsim.stop();
354  std::cout << "Time: " << tsim.getwct() << std::endl;
355 
356  // Google charts options, it store the options to draw the X Y graph
357  GCoptions options;
358 
359  // Title of the graph
360  options.title = std::string("Energy with time");
361 
362  // Y axis name
363  options.yAxis = std::string("Energy");
364 
365  // X axis name
366  options.xAxis = std::string("iteration");
367 
368  // width of the line
369  options.lineWidth = 1.0;
370 
371  // Object that draw the X Y graph
372  GoogleChart cg;
373 
374  // Add the graph
375  // The graph that it produce is in svg format that can be opened on browser
376  cg.AddLinesGraph(x,y,options);
377 
378  // Write into html format
379  cg.write("gc_plot2_out.html");
380 
381  openfpm_finalize();
382 }
void AddLinesGraph(openfpm::vector< X > &x, openfpm::vector< Y > &y, const GCoptions &opt)
Add a simple lines graph.
Class for Verlet list implementation.
std::string title
Title of the chart.
Definition: GoogleChart.hpp:28
This structure define the operation add to use with copy general.
This class implement the point shape in an N-dimensional space.
Definition: Point.hpp:27
double getwct()
Return the elapsed real time.
Definition: timer.hpp:130
Definition: Ghost.hpp:39
Implementation of VCluster class.
Definition: VCluster.hpp:58
std::string yAxis
Y axis name.
Definition: GoogleChart.hpp:30
Small class to produce graph with Google chart in HTML.
__device__ __host__ const T & get(unsigned int i) const
Get coordinate.
Definition: Point.hpp:172
void start()
Start the timer.
Definition: timer.hpp:90
size_t lineWidth
Width of the line.
Definition: GoogleChart.hpp:56
void write(std::string file)
It write the graphs on file in html format using Google charts.
Distributed vector.
aggregate of properties, from a list of object if create a struct that follow the OPENFPM native stru...
Definition: aggregate.hpp:214
Implementation of 1-D std::vector like structure.
Definition: map_vector.hpp:202
std::string xAxis
X axis name.
Definition: GoogleChart.hpp:32
Google chart options.
Definition: GoogleChart.hpp:25
Class for cpu time benchmarking.
Definition: timer.hpp:27
void stop()
Stop the timer.
Definition: timer.hpp:119