Repository navigation
Expand file tree
/
Copy pathmain.cpp
More file actions
409 lines (323 loc) · 10.3 KB
/
Copy pathmain.cpp
File metadata and controls
409 lines (323 loc) · 10.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
#include "Vector/vector_dist.hpp"
#include "data_type/aggregate.hpp"
#include "Plot/GoogleChart.hpp"
#include "Plot/util.hpp"
#include "timer.hpp"
/*!
* \page Vector_6_complex_usage Vector 6 complex usage for validation and debugging
*
* [TOC]
*
* # Complex usage for validation and debugging # {#e6_cp_deb}
*
* In this example we show how the flexibility of the library can be used to perform complex
* tasks for validation and debugging. We will use a lot of feature that has been explained in
* the previous examples
*
* In a previous example we show in case of symmetric interaction between particles how to symmetric
* cell list could be used to speed up the calculation.
*
* \see not present
*
* In this example we validate that both computation match, in particular because the computation depend
* from the neighborhood, we will check and validate that the neighborhood of each
* particle is equivalent with symmetric cell list and normal cell-list.
*
*/
int main(int argc, char* argv[])
{
/*!
* \page Vector_6_complex_usage Vector 6 complex usage for validation
*
* ## Initialization ##
*
* The initialization is classical we define cutoff radius, domain, boundary conditions,
* ghost part and some useful constants. We also define a struct that will contain the debug information. This structure
* contain an id that is the global id of the particle and a point that is the the position of the
* neighborhood.
*
* \see \ref e0_s_init
*
* \snippet Vector/6_complex_usage/main.cpp initialization
*
*/
//! \cond [initialization] \endcond
openfpm_init(&argc,&argv);
constexpr int gid = 0;
constexpr int nn_norm = 1;
constexpr int nn_sym = 2;
// used to define the domain
float L = 1000.0;
// Domain
Box<3,float> box({-L,-L,-L},{L,L,L});
// Boundary conditions
size_t bc[3]={PERIODIC,PERIODIC,PERIODIC};
// cut-off radius
float r_cut = 100.0;
// ghost
Ghost<3,float> ghost(r_cut);
// Point and global id
struct point_and_gid
{
// global id of the particle
size_t id;
// Position of the neighborhood particle
Point<3,float> xq;
// Used to reorder the neighborhood particles by id
bool operator<(const struct point_and_gid & pag) const
{
return (id < pag.id);
}
};
//! \cond [initialization] \endcond
/*!
* \page Vector_6_complex_usage Vector 6 complex usage for debugging
*
* ## Particle ##
*
* For this example we will use a particle with 3 properties
*
* * The first property is a global index for the particle unique across processors
* * The second is a vector that contain for each neighborhood the global id of the particle
* and its position
* * The last one is again a vector equivalent to the previous but is produced with the symmetric
* cell-list
*
* \snippet Vector/6_complex_usage/main.cpp particle prop
*
*/
//! \cond [particle prop] \endcond
// Particle properties list
typedef aggregate<size_t,openfpm::vector<point_and_gid>,openfpm::vector<point_and_gid>> part_prop;
//! \cond [particle prop] \endcond
/*!
* \page Vector_6_complex_usage Vector 6 complex usage for debugging
*
* ## Distributed vector ##
*
* Here we create a distributed vector of 4096 particles. We initialize the particles
* randomly and we assign a global index to the first property of the particle
*
* The function accum return the following number
*
* \f$ \sum_{i < proc} size\_local(i) \f$
*
* where \f$ proc \f$ is the processor where we are computing the formula and \f$ size\_local(i) \f$
* is the number of particles the processor \f$ i \f$ has. This number is used to
* produce a global id of the particles
*
* \snippet Vector/6_complex_usage/main.cpp glob id part
*
*/
//! \cond [glob id part] \endcond
// Distributed vector
vector_dist<3,float, part_prop > vd(4096,box,bc,ghost);
// used to calculate a global index for each particle
size_t start = vd.accum();
auto it = vd.getDomainIterator();
while (it.isNext())
{
auto key = it.get();
vd.getPos(key)[0] = 2.0*L*((float)rand()/RAND_MAX) - L;
vd.getPos(key)[1] = 2.0*L*((float)rand()/RAND_MAX) - L;
vd.getPos(key)[2] = 2.0*L*((float)rand()/RAND_MAX) - L;
vd.getProp<gid>(key) = key.getKey() + start;
++it;
}
//! \cond [glob id part] \endcond
/*!
* \page Vector_6_complex_usage Vector 6 complex usage for debugging
*
* ## Redistribute ##
*
* Redistribute the particles and synchronize the ghosts. In this case we
* are only interested in synchronizing the global id property.
*
* \snippet Vector/6_complex_usage/main.cpp map and ghost
*
*/
//! \cond [map and ghost] \endcond
vd.map();
// sync the ghost
vd.ghost_get<gid>();
//! \cond [map and ghost] \endcond
/*!
* \page Vector_6_complex_usage Vector 6 complex usage for debugging
*
* ## Calculate the neighborhood of each particle ##
*
* Here we calculate the neighborhood of each particles using a simple **cell list**.
* In case the particle q has a distance from the particle p smaller than r_cut.
* We add it in the first list of neighborhood
*
* \snippet Vector/6_complex_usage/main.cpp add nn particles
*
*/
//! \cond [add nn particles] \endcond
auto NN = vd.getCellList(r_cut);
auto p_it = vd.getDomainIterator();
while (p_it.isNext())
{
auto p = p_it.get();
Point<3,float> xp = vd.getPos(p);
auto Np = NN.getNNIteratorBox(NN.getCell(vd.getPos(p)));
while (Np.isNext())
{
auto q = Np.get();
// skip self interaction
if (p.getKey() == q)
{
++Np;
continue;
}
Point<3,float> xq = vd.getPos(q);
Point<3,float> f = (xp - xq);
float distance = f.norm();
// if the distance smalle than the cut-off radius add it to the neighborhood list
if (distance < r_cut )
{
vd.getProp<nn_norm>(p).add();
vd.getProp<nn_norm>(p).last().xq = xq;
vd.getProp<nn_norm>(p).last().id = vd.getProp<0>(q);
}
// Next neighborhood
++Np;
}
// Next particle
++p_it;
}
//! \cond [add nn particles] \endcond
/*!
* \page Vector_6_complex_usage Vector 6 complex usage for debugging
*
* ## Calculate the neighborhood of each particle with symmetric cell-list ##
*
* Here we calculate the neighborhood of each particle using instead a
* **symmetric cell list**. In case of symmetric cell-list if we find that a
* particle p is neighborhood of particle q we have to add p to the neighborhood
* of q and q to the neighborhood of p. Because q can be a ghost particle when
* we add the neighborhood p to q we have to transmit such information to the real
* owner of the particle. This can be done with the function **ghost_put**. In this
* case we use the operation **merge_** that add the already calculated neighborhood
* with the transmitted one. More in general it merge the information together.
*
* \snippet Vector/6_complex_usage/main.cpp add nn particles sym
*
*/
//! \cond [add nn particles sym] \endcond
auto NN2 = vd.getCellListSym(r_cut);
auto p_it2 = vd.getDomainIterator();
while (p_it2.isNext())
{
auto p = p_it2.get();
Point<3,float> xp = vd.getPos(p);
auto Np = NN2.getNNIteratorBoxSym(NN2.getCell(vd.getPos(p)),p.getKey(),vd.getPosVector());
while (Np.isNext())
{
auto q = Np.get();
if (p.getKey() == q)
{
++Np;
continue;
}
// repulsive
Point<3,float> xq = vd.getPos(q);
Point<3,float> f = (xp - xq);
float distance = f.norm();
// Particle should be inside r_cut range
if (distance < r_cut )
{
vd.getProp<nn_sym>(p).add();
vd.getProp<nn_sym>(q).add();
vd.getProp<nn_sym>(p).last().xq = xq;
vd.getProp<nn_sym>(q).last().xq = xp;
vd.getProp<nn_sym>(p).last().id = vd.getProp<0>(q);
vd.getProp<nn_sym>(q).last().id = vd.getProp<0>(p);
}
++Np;
}
++p_it2;
}
vd.ghost_put<merge_,2>();
//! \cond [add nn particles sym] \endcond
/*!
* \page Vector_6_complex_usage Vector 6 complex usage for debugging
*
* ## Cheking for validation ##
*
* Here we check that the two calculated neighborhood match. In particular,
* because the order of the particles does not match, we have to first reorder
* by global-id, and than check the list. We cannot instead easily compare the
* position. The reason can be seen in this figure
*
\verbatim
+----------------+
| |
| 1 |
| * 2 |
| 3 * |
+<----- ghost * +<-------- real
|* <--- real |* <------- ghost
|4 |4
| |
| |
+----------------+
\endverbatim
*
* In the case we are calculating the neighborhood of the particle \f$ + \f$ in case of normal Cell-list.
* The real particle 1,2,3 are added, while the particle 4 is added with the ghost particle coordinates.
* In the case of symmetric cell-list the real 1,2,3 are added to \f$ + \f$. The particle 4
* instead is added by the ghost put. In particular 4 real add the particle to the \f$ + \f$ ghost particle
* and than ghost put merge the information. This mean that the symmetric add the particle 4 with the real coordinates
* of the particle 4
*
* \snippet Vector/6_complex_usage/main.cpp checking
*
*/
//! \cond [checking] \endcond
auto p_it3 = vd.getDomainIterator();
bool ret = true;
while (p_it3.isNext())
{
auto p = p_it3.get();
vd.getProp<nn_norm>(p).sort();
vd.getProp<nn_sym>(p).sort();
ret &= vd.getProp<nn_norm>(p).size() == vd.getProp<nn_sym>(p).size();
for (size_t i = 0 ; i < vd.getProp<1>(p).size() ; i++)
{
ret &= vd.getProp<nn_norm>(p).get(i).id == vd.getProp<nn_sym>(p).get(i).id;
if (box.isInside(vd.getProp<nn_norm>(p).get(i).xq) == true)
{
ret &= vd.getProp<nn_norm>(p).get(i).xq == vd.getProp<nn_sym>(p).get(i).xq;
}
}
++p_it3;
}
if (ret != true)
{
std::cout << "ERROR" << std::endl;
exit(1);
}
//! \cond [checking] \endcond
/*!
* \page Vector_6_complex_usage Vector 6 complex usage for validation and debugging
*
* ## Finalize ##
*
* At the very end of the program we have always to de-initialize the library
*
* \snippet Vector/6_complex_usage/main.cpp finalize
*
*/
//! \cond [finalize] \endcond
openfpm_finalize();
//! \cond [finalize] \endcond
/*!
* \page Vector_6_complex_usage Vector 6 complex usage for validation and debugging
*
* # Full code # {#code}
*
* \include Vector/6_complex_usage/main.cpp
*
*/
}