Minkowski test code.
[voro++.git] / trunk / src / c_loops.hh
blob67bc5a44b711200fbbdd97274258a5545dc7ff67
1 // Voro++, a 3D cell-based Voronoi library
2 //
3 // Author : Chris H. Rycroft (LBL / UC Berkeley)
4 // Email : chr@alum.mit.edu
5 // Date : August 30th 2011
7 /** \file c_loops.hh
8 * \brief Header file for the loop classes. */
10 #ifndef VOROPP_C_LOOPS_HH
11 #define VOROPP_C_LOOPS_HH
13 #include "config.hh"
15 namespace voro {
17 /** A type associated with a c_loop_subset class, determining what type of
18 * geometrical region to loop over. */
19 enum c_loop_subset_mode {
20 sphere,
21 box,
22 no_check
25 /** \brief A class for storing ordering information when particles are added to
26 * a container.
28 * When particles are added to a container class, they are sorted into an
29 * internal computational grid of blocks. The particle_order class provides a
30 * mechanism for remembering which block particles were sorted into. The import
31 * and put routines in the container class have variants that also take a
32 * particle_order class. Each time they are called, they will store the block
33 * that the particle was sorted into, plus the position of the particle within
34 * the block. The particle_order class can used by the c_loop_order class to
35 * specifically loop over the particles that have their information stored
36 * within it. */
37 class particle_order {
38 public:
39 /** A pointer to the array holding the ordering. */
40 int *o;
41 /** A pointer to the next position in the ordering array in
42 * which to store an entry. */
43 int *op;
44 /** The current memory allocation for the class, set to the
45 * number of entries which can be stored. */
46 int size;
47 /** The particle_order constructor allocates memory to store the
48 * ordering information.
49 * \param[in] init_size the initial amount of memory to
50 * allocate. */
51 particle_order(int init_size=init_ordering_size)
52 : o(new int[init_size<<1]),op(o),size(init_size) {}
53 /** The particle_order destructor frees the dynamically allocated
54 * memory used to store the ordering information. */
55 ~particle_order() {
56 delete [] o;
58 /** Adds a record to the order, corresponding to the memory
59 * address of where a particle was placed into the container.
60 * \param[in] ijk the block into which the particle was placed.
61 * \param[in] q the position within the block where the
62 * particle was placed. */
63 inline void add(int ijk,int q) {
64 if(op==o+size) add_ordering_memory();
65 *(op++)=ijk;*(op++)=q;
67 private:
68 void add_ordering_memory();
71 /** \brief Base class for looping over particles in a container.
73 * This class forms the base of all classes that can loop over a subset of
74 * particles in a contaner in some order. When initialized, it stores constants
75 * about the corresponding container geometry. It also contains a number of
76 * routines for interrogating which particle currently being considered by the
77 * loop, which are common between all of the derived classes. */
78 class c_loop_base {
79 public:
80 /** The number of blocks in the x direction. */
81 const int nx;
82 /** The number of blocks in the y direction. */
83 const int ny;
84 /** The number of blocks in the z direction. */
85 const int nz;
86 /** A constant, set to the value of nx multiplied by ny, which
87 * is used in the routines that step through blocks in
88 * sequence. */
89 const int nxy;
90 /** A constant, set to the value of nx*ny*nz, which is used in
91 * the routines that step through blocks in sequence. */
92 const int nxyz;
93 /** The number of floating point numbers per particle in the
94 * associated container data structure. */
95 const int ps;
96 /** A pointer to the particle position information in the
97 * associated container data structure. */
98 double **p;
99 /** A pointer to the particle ID information in the associated
100 * container data structure. */
101 int **id;
102 /** A pointer to the particle counts in the associated
103 * container data structure. */
104 int *co;
105 /** The current x-index of the block under consideration by the
106 * loop. */
107 int i;
108 /** The current y-index of the block under consideration by the
109 * loop. */
110 int j;
111 /** The current z-index of the block under consideration by the
112 * loop. */
113 int k;
114 /** The current index of the block under consideration by the
115 * loop. */
116 int ijk;
117 /** The index of the particle under consideration within the current
118 * block. */
119 int q;
120 /** The constructor copies several necessary constants from the
121 * base container class.
122 * \param[in] con the container class to use. */
123 template<class c_class>
124 c_loop_base(c_class &con) : nx(con.nx), ny(con.ny), nz(con.nz),
125 nxy(con.nxy), nxyz(con.nxyz), ps(con.ps),
126 p(con.p), id(con.id), co(con.co) {}
127 /** Returns the position vector of the particle currently being
128 * considered by the loop.
129 * \param[out] (x,y,z) the position vector of the particle. */
130 inline void pos(double &x,double &y,double &z) {
131 double *pp=p[ijk]+ps*q;
132 x=*(pp++);y=*(pp++);z=*pp;
134 /** Returns the ID, position vector, and radius of the particle
135 * currently being considered by the loop.
136 * \param[out] pid the particle ID.
137 * \param[out] (x,y,z) the position vector of the particle.
138 * \param[out] r the radius of the particle. If no radius
139 * information is available the default radius
140 * value is returned. */
141 inline void pos(int &pid,double &x,double &y,double &z,double &r) {
142 pid=id[ijk][q];
143 double *pp=p[ijk]+ps*q;
144 x=*(pp++);y=*(pp++);z=*pp;
145 r=ps==3?default_radius:*(++pp);
147 /** Returns the x position of the particle currently being
148 * considered by the loop. */
149 inline double x() {return p[ijk][ps*q];}
150 /** Returns the y position of the particle currently being
151 * considered by the loop. */
152 inline double y() {return p[ijk][ps*q+1];}
153 /** Returns the z position of the particle currently being
154 * considered by the loop. */
155 inline double z() {return p[ijk][ps*q+2];}
156 /** Returns the ID of the particle currently being considered
157 * by the loop. */
158 inline int pid() {return id[ijk][q];}
161 /** \brief Class for looping over all of the particles in a container.
163 * This is one of the simplest loop classes, that scans the computational
164 * blocks in order, and scans all the particles within each block in order. */
165 class c_loop_all : public c_loop_base {
166 public:
167 /** The constructor copies several necessary constants from the
168 * base container class.
169 * \param[in] con the container class to use. */
170 template<class c_class>
171 c_loop_all(c_class &con) : c_loop_base(con) {}
172 /** Sets the class to consider the first particle.
173 * \return True if there is any particle to consider, false
174 * otherwise. */
175 inline bool start() {
176 i=j=k=ijk=q=0;
177 while(co[ijk]==0) if(!next_block()) return false;
178 return true;
180 /** Finds the next particle to test.
181 * \return True if there is another particle, false if no more
182 * particles are available. */
183 inline bool inc() {
184 q++;
185 if(q>=co[ijk]) {
186 q=0;
187 do {
188 if(!next_block()) return false;
189 } while(co[ijk]==0);
191 return true;
193 private:
194 /** Updates the internal variables to find the next
195 * computational block with any particles.
196 * \return True if another block is found, false if there are
197 * no more blocks. */
198 inline bool next_block() {
199 ijk++;
200 i++;
201 if(i==nx) {
202 i=0;j++;
203 if(j==ny) {
204 j=0;k++;
205 if(ijk==nxyz) return false;
208 return true;
212 /** \brief Class for looping over a subset of particles in a container.
214 * This class can loop over a subset of particles in a certain geometrical
215 * region within the container. The class can be set up to loop over a
216 * rectangular box or sphere. It can also rectangular group of internal
217 * computational blocks. */
218 class c_loop_subset : public c_loop_base {
219 public:
220 /** The current mode of operation, determining whether tests
221 * should be applied to particles to ensure they are within a
222 * certain geometrical object. */
223 c_loop_subset_mode mode;
224 /** The constructor copies several necessary constants from the
225 * base container class.
226 * \param[in] con the container class to use. */
227 template<class c_class>
228 c_loop_subset(c_class &con) : c_loop_base(con), ax(con.ax), ay(con.ay), az(con.az),
229 sx(con.bx-ax), sy(con.by-ay), sz(con.bz-az), xsp(con.xsp), ysp(con.ysp), zsp(con.zsp),
230 xperiodic(con.xperiodic), yperiodic(con.yperiodic), zperiodic(con.zperiodic) {}
231 void setup_sphere(double vx,double vy,double vz,double r,bool bounds_test=true);
232 void setup_box(double xmin,double xmax,double ymin,double ymax,double zmin,double zmax,bool bounds_test=true);
233 void setup_intbox(int ai_,int bi_,int aj_,int bj_,int ak_,int bk_);
234 bool start();
235 /** Finds the next particle to test.
236 * \return True if there is another particle, false if no more
237 * particles are available. */
238 inline bool inc() {
239 do {
240 q++;
241 while(q>=co[ijk]) {q=0;if(!next_block()) return false;}
242 } while(mode!=no_check&&out_of_bounds());
243 return true;
245 private:
246 const double ax,ay,az,sx,sy,sz,xsp,ysp,zsp;
247 const bool xperiodic,yperiodic,zperiodic;
248 double px,py,pz,apx,apy,apz;
249 double v0,v1,v2,v3,v4,v5;
250 int ai,bi,aj,bj,ak,bk;
251 int ci,cj,ck,di,dj,dk,inc1,inc2;
252 inline int step_mod(int a,int b) {return a>=0?a%b:b-1-(b-1-a)%b;}
253 inline int step_div(int a,int b) {return a>=0?a/b:-1+(a+1)/b;}
254 inline int step_int(double a) {return a<0?int(a)-1:int(a);}
255 void setup_common();
256 bool next_block();
257 bool out_of_bounds();
260 /** \brief Class for looping over all of the particles specified in a
261 * pre-assembled particle_order class.
263 * The particle_order class can be used to create a specific order of particles
264 * within the container. This class can then loop over these particles in this
265 * order. The class is particularly useful in cases where the ordering of the
266 * output must match the ordering of particles as they were inserted into the
267 * container. */
268 class c_loop_order : public c_loop_base {
269 public:
270 /** A reference to the ordering class to use. */
271 particle_order &vo;
272 /** A pointer to the current position in the ordering class. */
273 int *cp;
274 /** A pointer to the end position in the ordering class. */
275 int *op;
276 /** The constructor copies several necessary constants from the
277 * base class, and sets up a reference to the ordering class to
278 * use.
279 * \param[in] con the container class to use.
280 * \param[in] vo_ the ordering class to use. */
281 template<class c_class>
282 c_loop_order(c_class &con,particle_order &vo_)
283 : c_loop_base(con), vo(vo_), nx(con.nx), nxy(con.nxy) {}
284 /** Sets the class to consider the first particle.
285 * \return True if there is any particle to consider, false
286 * otherwise. */
287 inline bool start() {
288 cp=vo.o;op=vo.op;
289 if(cp!=op) {
290 ijk=*(cp++);decode();
291 q=*(cp++);
292 return true;
293 } else return false;
295 /** Finds the next particle to test.
296 * \return True if there is another particle, false if no more
297 * particles are available. */
298 inline bool inc() {
299 if(cp==op) return false;
300 ijk=*(cp++);decode();
301 q=*(cp++);
302 return true;
304 private:
305 /** The number of computational blocks in the x direction. */
306 const int nx;
307 /** The number of computational blocks in a z-slice. */
308 const int nxy;
309 /** Takes the current block index and computes indices in the
310 * x, y, and z directions. */
311 inline void decode() {
312 k=ijk/nxy;
313 int ijkt=ijk-nxy*k;
314 j=ijkt/nx;
315 i=ijkt-j*nx;
319 /** \brief A class for looping over all particles in a container_periodic or
320 * container_periodic_poly class.
322 * Since the container_periodic and container_periodic_poly classes have a
323 * fundamentally different memory organization, the regular loop classes cannot
324 * be used with them. */
325 class c_loop_all_periodic : public c_loop_base {
326 public:
327 /** The constructor copies several necessary constants from the
328 * base periodic container class.
329 * \param[in] con the periodic container class to use. */
330 template<class c_class>
331 c_loop_all_periodic(c_class &con) : c_loop_base(con), ey(con.ey), ez(con.ez), wy(con.wy), wz(con.wz),
332 ijk0(nx*(ey+con.oy*ez)), inc2(2*nx*con.ey+1) {}
333 /** Sets the class to consider the first particle.
334 * \return True if there is any particle to consider, false
335 * otherwise. */
336 inline bool start() {
337 i=0;
338 j=ey;
339 k=ez;
340 ijk=ijk0;
341 q=0;
342 while(co[ijk]==0) if(!next_block()) return false;
343 return true;
345 /** Finds the next particle to test.
346 * \return True if there is another particle, false if no more
347 * particles are available. */
348 inline bool inc() {
349 q++;
350 if(q>=co[ijk]) {
351 q=0;
352 do {
353 if(!next_block()) return false;
354 } while(co[ijk]==0);
356 return true;
358 private:
359 /** The lower y index (inclusive) of the primary domain within
360 * the block structure. */
361 int ey;
362 /** The lower y index (inclusive) of the primary domain within
363 * the block structure. */
364 int ez;
365 /** The upper y index (exclusive) of the primary domain within
366 * the block structure. */
367 int wy;
368 /** The upper z index (exclusive) of the primary domain within
369 * the block structure. */
370 int wz;
371 /** The index of the (0,0,0) block within the block structure.
373 int ijk0;
374 /** A value to increase ijk by when the z index is increased.
376 int inc2;
377 /** Updates the internal variables to find the next
378 * computational block with any particles.
379 * \return True if another block is found, false if there are
380 * no more blocks. */
381 inline bool next_block() {
382 i++;
383 if(i==nx) {
384 i=0;j++;
385 if(j==wy) {
386 j=ey;k++;
387 if(k==wz) return false;
388 ijk+=inc2;
389 } else ijk++;
390 } else ijk++;
391 return true;
395 /** \brief Class for looping over all of the particles specified in a
396 * pre-assembled particle_order class, for use with container_periodic classes.
398 * The particle_order class can be used to create a specific order of particles
399 * within the container. This class can then loop over these particles in this
400 * order. The class is particularly useful in cases where the ordering of the
401 * output must match the ordering of particles as they were inserted into the
402 * container. */
403 class c_loop_order_periodic : public c_loop_base {
404 public:
405 /** A reference to the ordering class to use. */
406 particle_order &vo;
407 /** A pointer to the current position in the ordering class. */
408 int *cp;
409 /** A pointer to the end position in the ordering class. */
410 int *op;
411 /** The constructor copies several necessary constants from the
412 * base class, and sets up a reference to the ordering class to
413 * use.
414 * \param[in] con the container class to use.
415 * \param[in] vo_ the ordering class to use. */
416 template<class c_class>
417 c_loop_order_periodic(c_class &con,particle_order &vo_)
418 : c_loop_base(con), vo(vo_), nx(con.nx), oxy(con.nx*con.oy) {}
419 /** Sets the class to consider the first particle.
420 * \return True if there is any particle to consider, false
421 * otherwise. */
422 inline bool start() {
423 cp=vo.o;op=vo.op;
424 if(cp!=op) {
425 ijk=*(cp++);decode();
426 q=*(cp++);
427 return true;
428 } else return false;
430 /** Finds the next particle to test.
431 * \return True if there is another particle, false if no more
432 * particles are available. */
433 inline bool inc() {
434 if(cp==op) return false;
435 ijk=*(cp++);decode();
436 q=*(cp++);
437 return true;
439 private:
440 /** The number of computational blocks in the x direction. */
441 const int nx;
442 /** The number of computational blocks in a z-slice. */
443 const int oxy;
444 /** Takes the current block index and computes indices in the
445 * x, y, and z directions. */
446 inline void decode() {
447 k=ijk/oxy;
448 int ijkt=ijk-oxy*k;
449 j=ijkt/nx;
450 i=ijkt-j*nx;
456 #endif