Voro++
c_loops.hh
Go to the documentation of this file.
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
6 
7 /** \file c_loops.hh
8  * \brief Header file for the loop classes. */
9 
10 #ifndef VOROPP_C_LOOPS_HH
11 #define VOROPP_C_LOOPS_HH
12 
13 #include "config.hh"
14 
15 namespace voro {
16 
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
23 };
24 
25 /** \brief A class for storing ordering information when particles are added to
26  * a container.
27  *
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. */
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. */
56  delete [] o;
57  }
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;
66  }
67  private:
68  void add_ordering_memory();
69 };
70 
71 /** \brief Base class for looping over particles in a container.
72  *
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;
133  }
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);
146  }
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];}
159 };
160 
161 /** \brief Class for looping over all of the particles in a container.
162  *
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;
179  }
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);
190  }
191  return true;
192  }
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;
206  }
207  }
208  return true;
209  }
210 };
211 
212 /** \brief Class for looping over a subset of particles in a container.
213  *
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;
244  }
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();
258 };
259 
260 /** \brief Class for looping over all of the particles specified in a
261  * pre-assembled particle_order class.
262  *
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. */
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;
294  }
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;
303  }
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;
316  }
317 };
318 
319 /** \brief A class for looping over all particles in a container_periodic or
320  * container_periodic_poly class.
321  *
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. */
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;
344  }
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);
355  }
356  return true;
357  }
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.
372  */
373  int ijk0;
374  /** A value to increase ijk by when the z index is increased.
375  */
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;
392  }
393 };
394 
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.
397  *
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. */
404  public:
405  /** A reference to the ordering class to use. */
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>
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;
429  }
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;
438  }
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;
451  }
452 };
453 
454 }
455 
456 #endif
Class for looping over all of the particles in a container.
Definition: c_loops.hh:165
c_loop_all(c_class &con)
Definition: c_loops.hh:171
c_loop_base(c_class &con)
Definition: c_loops.hh:124
const int ps
Definition: c_loops.hh:95
Master configuration file for setting various compile-time options.
c_loop_order_periodic(c_class &con, particle_order &vo_)
Definition: c_loops.hh:417
const int nz
Definition: c_loops.hh:85
void setup_box(double xmin, double xmax, double ymin, double ymax, double zmin, double zmax, bool bounds_test=true)
Definition: c_loops.cc:98
Class for looping over all of the particles specified in a pre-assembled particle_order class...
Definition: c_loops.hh:403
double ** p
Definition: c_loops.hh:98
Class for looping over all of the particles specified in a pre-assembled particle_order class...
Definition: c_loops.hh:268
particle_order & vo
Definition: c_loops.hh:271
void pos(double &x, double &y, double &z)
Definition: c_loops.hh:130
c_loop_order(c_class &con, particle_order &vo_)
Definition: c_loops.hh:282
const int nxyz
Definition: c_loops.hh:92
const int nx
Definition: c_loops.hh:81
c_loop_subset_mode mode
Definition: c_loops.hh:223
void pos(int &pid, double &x, double &y, double &z, double &r)
Definition: c_loops.hh:141
Class for looping over a subset of particles in a container.
Definition: c_loops.hh:218
void add(int ijk, int q)
Definition: c_loops.hh:63
const int ny
Definition: c_loops.hh:83
void setup_intbox(int ai_, int bi_, int aj_, int bj_, int ak_, int bk_)
Definition: c_loops.cc:44
c_loop_subset(c_class &con)
Definition: c_loops.hh:228
particle_order & vo
Definition: c_loops.hh:406
particle_order(int init_size=init_ordering_size)
Definition: c_loops.hh:51
Base class for looping over particles in a container.
Definition: c_loops.hh:78
A class for looping over all particles in a container_periodic or container_periodic_poly class...
Definition: c_loops.hh:325
void setup_sphere(double vx, double vy, double vz, double r, bool bounds_test=true)
Definition: c_loops.cc:24
const int nxy
Definition: c_loops.hh:89
A class for storing ordering information when particles are added to a container. ...
Definition: c_loops.hh:37
c_loop_all_periodic(c_class &con)
Definition: c_loops.hh:331