OpenFPM_pdata  4.1.0
Project that contain the implementation of distributed structures
main.cu
1 #define SCAN_WITH_CUB
2 
75 #ifdef __NVCC__
76 
77 #include "Vector/vector_dist.hpp"
78 #include "Plot/GoogleChart.hpp"
79 #include "Plot/util.hpp"
80 #include "timer.hpp"
81 
82 #ifdef TEST_RUN
83 size_t nstep = 100;
84 #else
85 size_t nstep = 1000;
86 #endif
87 
88 typedef float real_number;
89 
91 
92 constexpr int velocity = 0;
93 constexpr int force = 1;
94 constexpr int energy = 2;
95 
97 
98 template<typename vector_dist_type,typename NN_type>
99 __global__ void calc_force_gpu(vector_dist_type vd, NN_type NN, real_number sigma12, real_number sigma6, real_number r_cut2)
100 {
101  auto p = GET_PARTICLE(vd);
102 
103  // Get the position xp of the particle
104  Point<3,real_number> xp = vd.getPos(p);
105 
106  // Reset the force counter
107  vd.template getProp<force>(p)[0] = 0.0;
108  vd.template getProp<force>(p)[1] = 0.0;
109  vd.template getProp<force>(p)[2] = 0.0;
110 
111 
112 
113  // Get an iterator over the neighborhood particles of p
114  auto Np = NN.getNNIterator(NN.getCell(vd.getPos(p)));
115 
116  // For each neighborhood particle ...
117  while (Np.isNext())
118  {
119  // ... q
120  auto q = Np.get();
121 
122  // if (p == q) skip this particle
123  if (q == p) {++Np; continue;};
124 
125  // Get the position of p
126  Point<3,real_number> xq = vd.getPos(q);
127 
128  // Get the distance between p and q
129  Point<3,real_number> r = xp - xq;
130 
131  // take the norm of this vector
132  real_number rn = norm2(r);
133 
134  if (rn > r_cut2)
135  {++Np; continue;};
136 
137  // Calculate the force, using pow is slower
138  Point<3,real_number> f = 24.0*(2.0 *sigma12 / (rn*rn*rn*rn*rn*rn*rn) - sigma6 / (rn*rn*rn*rn)) * r;
139 
140  // we sum the force produced by q on p
141  vd.template getProp<force>(p)[0] += f.get(0);
142  vd.template getProp<force>(p)[1] += f.get(1);
143  vd.template getProp<force>(p)[2] += f.get(2);
144 
145  // Next neighborhood
146  ++Np;
147  }
148 }
149 
151 
152 template<typename vector_dist_type>
153 __global__ void update_velocity_position(vector_dist_type vd, real_number dt)
154 {
155  auto p = GET_PARTICLE(vd);
156 
157  // here we calculate v(tn + 0.5)
158  vd.template getProp<velocity>(p)[0] += 0.5*dt*vd.template getProp<force>(p)[0];
159  vd.template getProp<velocity>(p)[1] += 0.5*dt*vd.template getProp<force>(p)[1];
160  vd.template getProp<velocity>(p)[2] += 0.5*dt*vd.template getProp<force>(p)[2];
161 
162  // here we calculate x(tn + 1)
163  vd.getPos(p)[0] += vd.template getProp<velocity>(p)[0]*dt;
164  vd.getPos(p)[1] += vd.template getProp<velocity>(p)[1]*dt;
165  vd.getPos(p)[2] += vd.template getProp<velocity>(p)[2]*dt;
166 }
167 
168 template<typename vector_dist_type>
169 __global__ void update_velocity(vector_dist_type vd, real_number dt)
170 {
171  auto p = GET_PARTICLE(vd);
172 
173  // here we calculate v(tn + 1)
174  vd.template getProp<velocity>(p)[0] += 0.5*dt*vd.template getProp<force>(p)[0];
175  vd.template getProp<velocity>(p)[1] += 0.5*dt*vd.template getProp<force>(p)[1];
176  vd.template getProp<velocity>(p)[2] += 0.5*dt*vd.template getProp<force>(p)[2];
177 }
178 
180 
182 
183 template<typename vector_dist_type,typename NN_type>
184 __global__ void particle_energy(vector_dist_type vd, NN_type NN, real_number sigma12, real_number sigma6, real_number shift, real_number r_cut2)
185 {
186  auto p = GET_PARTICLE(vd);
187 
188  // Get the position of the particle p
189  Point<3,real_number> xp = vd.getPos(p);
190 
191  // Get an iterator over the neighborhood of the particle p
192  auto Np = NN.getNNIterator(NN.getCell(vd.getPos(p)));
193 
194  real_number E = 0;
195 
196  // For each neighborhood of the particle p
197  while (Np.isNext())
198  {
199  // Neighborhood particle q
200  auto q = Np.get();
201 
202  // if p == q skip this particle
203  if (q == p) {++Np; continue;};
204 
205  // Get position of the particle q
206  Point<3,real_number> xq = vd.getPos(q);
207 
208  // take the normalized direction
209  real_number rn = norm2(xp - xq);
210 
211  if (rn > r_cut2)
212  {++Np;continue;}
213 
214  // potential energy (using pow is slower)
215  E += 2.0 * ( sigma12 / (rn*rn*rn*rn*rn*rn) - sigma6 / ( rn*rn*rn) ) - shift;
216 
217  // Next neighborhood
218  ++Np;
219  }
220 
221  // Kinetic energy of the particle given by its actual speed
222  vd.template getProp<energy>(p) = E + (vd.template getProp<velocity>(p)[0]*vd.template getProp<velocity>(p)[0] +
223  vd.template getProp<velocity>(p)[1]*vd.template getProp<velocity>(p)[1] +
224  vd.template getProp<velocity>(p)[2]*vd.template getProp<velocity>(p)[2]) / 2;
225 }
226 
228 
230 
231 template<typename CellList> void calc_forces(vector_dist_gpu<3,real_number, aggregate<real_number[3],real_number[3],real_number> > & vd, CellList & NN, real_number sigma12, real_number sigma6, real_number r_cut2)
232 {
233  vd.updateCellList(NN);
234 
235  // Get an iterator over particles
236  auto it2 = vd.getDomainIteratorGPU();
237 
238  CUDA_LAUNCH(calc_force_gpu,it2,vd.toKernel(),NN.toKernel(),sigma12,sigma6,r_cut2);
239 }
240 
242 
243 template<typename CellList> real_number calc_energy(vector_dist_gpu<3,real_number, aggregate<real_number[3],real_number[3],real_number> > & vd, CellList & NN, real_number sigma12, real_number sigma6, real_number r_cut2)
244 {
245  real_number rc = r_cut2;
246  real_number shift = 2.0 * ( sigma12 / (rc*rc*rc*rc*rc*rc) - sigma6 / ( rc*rc*rc) );
247 
248  vd.updateCellList(NN);
249 
250  auto it2 = vd.getDomainIteratorGPU();
251 
252  CUDA_LAUNCH(particle_energy,it2,vd.toKernel(),NN.toKernel(),sigma12,sigma6,shift,r_cut2);
253 
255 
256  // Calculated energy
257  return reduce_local<energy,_add_>(vd);
258 
260 }
261 
262 int main(int argc, char* argv[])
263 {
264  openfpm_init(&argc,&argv);
265 
266  real_number sigma = 0.01;
267  real_number r_cut = 3.0*sigma;
268 
269  // we will use it do place particles on a 10x10x10 Grid like
270  size_t sz[3] = {100,100,100};
271 
272  // domain
273  Box<3,float> box({0.0,0.0,0.0},{1.0,1.0,1.0});
274 
275  // Boundary conditions
276  size_t bc[3]={PERIODIC,PERIODIC,PERIODIC};
277 
278  // ghost, big enough to contain the interaction radius
279  Ghost<3,float> ghost(r_cut);
280 
281  real_number dt = 0.00005;
282  real_number sigma12 = pow(sigma,12);
283  real_number sigma6 = pow(sigma,6);
284 
287 
289 
290  // We create the grid iterator
291  auto it = vd.getGridIterator(sz);
292 
293  while (it.isNext())
294  {
295  // Create a new particle
296  vd.add();
297 
298  // key contain (i,j,k) index of the grid
299  auto key = it.get();
300 
301  // The index of the grid can be accessed with key.get(0) == i, key.get(1) == j ...
302  // We use getLastPos to set the position of the last particle added
303  vd.getLastPos()[0] = key.get(0) * it.getSpacing(0);
304  vd.getLastPos()[1] = key.get(1) * it.getSpacing(1);
305  vd.getLastPos()[2] = key.get(2) * it.getSpacing(2);
306 
307  // We use getLastProp to set the property value of the last particle we added
308  vd.template getLastProp<velocity>()[0] = 0.0;
309  vd.template getLastProp<velocity>()[1] = 0.0;
310  vd.template getLastProp<velocity>()[2] = 0.0;
311 
312  vd.template getLastProp<force>()[0] = 0.0;
313  vd.template getLastProp<force>()[1] = 0.0;
314  vd.template getLastProp<force>()[2] = 0.0;
315 
316  ++it;
317  }
318 
319  vd.hostToDevicePos();
320  vd.hostToDeviceProp<velocity,force>();
321 
322  vd.map(RUN_ON_DEVICE);
323  vd.ghost_get<>(RUN_ON_DEVICE);
324 
325  timer tsim;
326  tsim.start();
327 
329 
330  // Get the Cell list structure
331  auto NN = vd.getCellListGPU(r_cut);
332 
333  // The standard
334  // auto NN = vd.getCellList(r_cut);
335 
336  // calculate forces
337  calc_forces(vd,NN,sigma12,sigma6,r_cut*r_cut);
338  unsigned long int f = 0;
339 
340  // MD time stepping
341  for (size_t i = 0; i < nstep ; i++)
342  {
343  // Get the iterator
344  auto it3 = vd.getDomainIteratorGPU();
345 
346  CUDA_LAUNCH(update_velocity_position,it3,vd.toKernel(),dt);
347 
349 
350  // Because we moved the particles in space we have to map them and re-sync the ghost
351  vd.map(RUN_ON_DEVICE);
352  vd.template ghost_get<>(RUN_ON_DEVICE);
353 
355 
356  // calculate forces or a(tn + 1) Step 2
357  calc_forces(vd,NN,sigma12,sigma6,r_cut*r_cut);
358 
359 
360  // Integrate the velocity Step 3
361  auto it4 = vd.getDomainIteratorGPU();
362 
363  CUDA_LAUNCH(update_velocity,it4,vd.toKernel(),dt);
364 
365  // After every iteration collect some statistic about the configuration
366  if (i % 100 == 0)
367  {
369 
370  vd.deviceToHostPos();
371  vd.deviceToHostProp<0,1,2>();
372 
373  // We write the particle position for visualization (Without ghost)
374  vd.deleteGhost();
375  vd.write_frame("particles_",f);
376 
378 
379  // we resync the ghost
380  vd.ghost_get<>(RUN_ON_DEVICE);
381 
382  // We calculate the energy
383  real_number energy = calc_energy(vd,NN,sigma12,sigma6,r_cut*r_cut);
384  auto & vcl = create_vcluster();
385  vcl.sum(energy);
386  vcl.execute();
387 
388  // we save the energy calculated at time step i c contain the time-step y contain the energy
389  x.add(i);
390  y.add({energy});
391 
392  // We also print on terminal the value of the energy
393  // only one processor (master) write on terminal
394  if (vcl.getProcessUnitID() == 0)
395  std::cout << "Energy: " << energy << std::endl;
396 
397  f++;
398  }
399  }
400 
402 
403  tsim.stop();
404  std::cout << "Time: " << tsim.getwct() << std::endl;
405 
406  // Google charts options, it store the options to draw the X Y graph
407  GCoptions options;
408 
409  // Title of the graph
410  options.title = std::string("Energy with time");
411 
412  // Y axis name
413  options.yAxis = std::string("Energy");
414 
415  // X axis name
416  options.xAxis = std::string("iteration");
417 
418  // width of the line
419  options.lineWidth = 1.0;
420 
421  // Resolution in x
422  options.width = 1280;
423 
424  // Resolution in y
425  options.heigh = 720;
426 
427  // Add zoom capability
428  options.more = GC_ZOOM;
429 
430  // Object that draw the X Y graph
431  GoogleChart cg;
432 
433  // Add the graph
434  // The graph that it produce is in svg format that can be opened on browser
435  cg.AddLinesGraph(x,y,options);
436 
437  // Write into html format
438  cg.write("gc_plot2_out.html");
439 
440  openfpm_finalize();
441 }
442 
443 #else
444 
445 int main(int argc, char* argv[])
446 {
447  return 0;
448 }
449 
450 #endif
451 
452 
size_t heigh
height of the graph in pixels
Definition: GoogleChart.hpp:49
void AddLinesGraph(openfpm::vector< X > &x, openfpm::vector< Y > &y, const GCoptions &opt)
Add a simple lines graph.
std::string title
Title of the chart.
Definition: GoogleChart.hpp:28
std::string more
more
Definition: GoogleChart.hpp:67
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
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.
size_t width
width of the graph in pixels
Definition: GoogleChart.hpp:46
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
Class for FAST cell list implementation.
Definition: CellList.hpp:356
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