Voro++
|
00001 // Voro++, a 3D cell-based Voronoi library 00002 // 00003 // Author : Chris H. Rycroft (LBL / UC Berkeley) 00004 // Email : chr@alum.mit.edu 00005 // Date : August 30th 2011 00006 00007 /** \file c_loops.hh 00008 * \brief Header file for the loop classes. */ 00009 00010 #ifndef VOROPP_C_LOOPS_HH 00011 #define VOROPP_C_LOOPS_HH 00012 00013 #include <cstdio> 00014 #include <cstdlib> 00015 #include <cmath> 00016 #include <vector> 00017 using namespace std; 00018 00019 #include "config.hh" 00020 00021 namespace voro { 00022 00023 /** A type associated with a c_loop_subset class, determining what type of 00024 * geometrical region to loop over. */ 00025 enum c_loop_subset_mode { 00026 sphere, 00027 box, 00028 no_check 00029 }; 00030 00031 /** \brief A class for storing ordering information when particles are added to 00032 * a container. 00033 * 00034 * When particles are added to a container class, they are sorted into an 00035 * internal computational grid of blocks. The particle_order class provides a 00036 * mechanism for remembering which block particles were sorted into. The import 00037 * and put routines in the container class have variants that also take a 00038 * particle_order class. Each time they are called, they will store the block 00039 * that the particle was sorted into, plus the position of the particle within 00040 * the block. The particle_order class can used by the c_loop_order class to 00041 * specifically loop over the particles that have their information stored 00042 * within it. */ 00043 class particle_order { 00044 public: 00045 /** A pointer to the array holding the ordering. */ 00046 int *o; 00047 /** A pointer to the next position in the ordering array in 00048 * which to store an entry. */ 00049 int *op; 00050 /** The current memory allocation for the class, set to the 00051 * number of entries which can be stored. */ 00052 int size; 00053 /** The particle_order constructor allocates memory to store the 00054 * ordering information. 00055 * \param[in] init_size the initial amount of memory to 00056 * allocate. */ 00057 particle_order(int init_size=init_ordering_size) 00058 : o(new int[init_size<<1]),op(o),size(init_size) {} 00059 /** The particle_order destructor frees the dynamically allocated 00060 * memory used to store the ordering information. */ 00061 ~particle_order() { 00062 delete [] o; 00063 } 00064 /** Adds a record to the order, corresponding to the memory 00065 * address of where a particle was placed into the container. 00066 * \param[in] ijk the block into which the particle was placed. 00067 * \param[in] q the position within the block where the 00068 * particle was placed. */ 00069 inline void add(int ijk,int q) { 00070 if(op==o+size) add_ordering_memory(); 00071 *(op++)=ijk;*(op++)=q; 00072 } 00073 private: 00074 void add_ordering_memory(); 00075 }; 00076 00077 /** \brief Base class for looping over particles in a container. 00078 * 00079 * This class forms the base of all classes that can loop over a subset of 00080 * particles in a contaner in some order. When initialized, it stores constants 00081 * about the corresponding container geometry. It also contains a number of 00082 * routines for interrogating which particle currently being considered by the 00083 * loop, which are common between all of the derived classes. */ 00084 class c_loop_base { 00085 public: 00086 /** The number of blocks in the x direction. */ 00087 const int nx; 00088 /** The number of blocks in the y direction. */ 00089 const int ny; 00090 /** The number of blocks in the z direction. */ 00091 const int nz; 00092 /** A constant, set to the value of nx multiplied by ny, which 00093 * is used in the routines that step through blocks in 00094 * sequence. */ 00095 const int nxy; 00096 /** A constant, set to the value of nx*ny*nz, which is used in 00097 * the routines that step through blocks in sequence. */ 00098 const int nxyz; 00099 /** The number of floating point numbers per particle in the 00100 * associated container data structure. */ 00101 const int ps; 00102 /** A pointer to the particle position information in the 00103 * associated container data structure. */ 00104 double **p; 00105 /** A pointer to the particle ID information in the associated 00106 * container data structure. */ 00107 int **id; 00108 /** A pointer to the particle counts in the associated 00109 * container data structure. */ 00110 int *co; 00111 /** The current x-index of the block under consideration by the 00112 * loop. */ 00113 int i; 00114 /** The current y-index of the block under consideration by the 00115 * loop. */ 00116 int j; 00117 /** The current z-index of the block under consideration by the 00118 * loop. */ 00119 int k; 00120 /** The current index of the block under consideration by the 00121 * loop. */ 00122 int ijk; 00123 /** The index of the particle under consideration within the current 00124 * block. */ 00125 int q; 00126 /** The constructor copies several necessary constants from the 00127 * base container class. 00128 * \param[in] con the container class to use. */ 00129 template<class c_class> 00130 c_loop_base(c_class &con) : nx(con.nx), ny(con.ny), nz(con.nz), 00131 nxy(con.nxy), nxyz(con.nxyz), ps(con.ps), 00132 p(con.p), id(con.id), co(con.co) {} 00133 /** Returns the position vector of the particle currently being 00134 * considered by the loop. 00135 * \param[out] (x,y,z) the position vector of the particle. */ 00136 inline void pos(double &x,double &y,double &z) { 00137 double *pp=p[ijk]+ps*q; 00138 x=*(pp++);y=*(pp++);z=*pp; 00139 } 00140 /** Returns the ID, position vector, and radius of the particle 00141 * currently being considered by the loop. 00142 * \param[out] pid the particle ID. 00143 * \param[out] (x,y,z) the position vector of the particle. 00144 * \param[out] r the radius of the particle. If no radius 00145 * information is available the default radius 00146 * value is returned. */ 00147 inline void pos(int &pid,double &x,double &y,double &z,double &r) { 00148 pid=id[ijk][q]; 00149 double *pp=p[ijk]+ps*q; 00150 x=*(pp++);y=*(pp++);z=*pp; 00151 r=ps==3?default_radius:*(++pp); 00152 } 00153 /** Returns the x position of the particle currently being 00154 * considered by the loop. */ 00155 inline double x() {return p[ijk][ps*q];} 00156 /** Returns the y position of the particle currently being 00157 * considered by the loop. */ 00158 inline double y() {return p[ijk][ps*q+1];} 00159 /** Returns the z position of the particle currently being 00160 * considered by the loop. */ 00161 inline double z() {return p[ijk][ps*q+2];} 00162 /** Returns the ID of the particle currently being considered 00163 * by the loop. */ 00164 inline int pid() {return id[ijk][q];} 00165 }; 00166 00167 /** \brief Class for looping over all of the particles in a container. 00168 * 00169 * This is one of the simplest loop classes, that scans the computational 00170 * blocks in order, and scans all the particles within each block in order. */ 00171 class c_loop_all : public c_loop_base { 00172 public: 00173 /** The constructor copies several necessary constants from the 00174 * base container class. 00175 * \param[in] con the container class to use. */ 00176 template<class c_class> 00177 c_loop_all(c_class &con) : c_loop_base(con) {} 00178 /** Sets the class to consider the first particle. 00179 * \return True if there is any particle to consider, false 00180 * otherwise. */ 00181 inline bool start() { 00182 i=j=k=ijk=q=0; 00183 while(co[ijk]==0) if(!next_block()) return false; 00184 return true; 00185 } 00186 /** Finds the next particle to test. 00187 * \return True if there is another particle, false if no more 00188 * particles are available. */ 00189 inline bool inc() { 00190 q++; 00191 if(q>=co[ijk]) { 00192 q=0; 00193 do { 00194 if(!next_block()) return false; 00195 } while(co[ijk]==0); 00196 } 00197 return true; 00198 } 00199 private: 00200 /** Updates the internal variables to find the next 00201 * computational block with any particles. 00202 * \return True if another block is found, false if there are 00203 * no more blocks. */ 00204 inline bool next_block() { 00205 ijk++; 00206 i++; 00207 if(i==nx) { 00208 i=0;j++; 00209 if(j==ny) { 00210 j=0;k++; 00211 if(ijk==nxyz) return false; 00212 } 00213 } 00214 return true; 00215 } 00216 }; 00217 00218 /** \brief Class for looping over a subset of particles in a container. 00219 * 00220 * This class can loop over a subset of particles in a certain geometrical 00221 * region within the container. The class can be set up to loop over a 00222 * rectangular box or sphere. It can also rectangular group of internal 00223 * computational blocks. */ 00224 class c_loop_subset : public c_loop_base { 00225 public: 00226 /** The current mode of operation, determining whether tests 00227 * should be applied to particles to ensure they are within a 00228 * certain geometrical object. */ 00229 c_loop_subset_mode mode; 00230 /** The constructor copies several necessary constants from the 00231 * base container class. 00232 * \param[in] con the container class to use. */ 00233 template<class c_class> 00234 c_loop_subset(c_class &con) : c_loop_base(con), ax(con.ax), ay(con.ay), az(con.az), 00235 sx(con.bx-ax), sy(con.by-ay), sz(con.bz-az), xsp(con.xsp), ysp(con.ysp), zsp(con.zsp), 00236 xperiodic(con.xperiodic), yperiodic(con.yperiodic), zperiodic(con.zperiodic) {} 00237 void setup_sphere(double vx,double vy,double vz,double r,bool bounds_test=true); 00238 void setup_box(double xmin,double xmax,double ymin,double ymax,double zmin,double zmax,bool bounds_test=true); 00239 void setup_intbox(int ai_,int bi_,int aj_,int bj_,int ak_,int bk_); 00240 bool start(); 00241 /** Finds the next particle to test. 00242 * \return True if there is another particle, false if no more 00243 * particles are available. */ 00244 inline bool inc() { 00245 do { 00246 q++; 00247 while(q>=co[ijk]) {q=0;if(!next_block()) return false;} 00248 } while(mode!=no_check&&out_of_bounds()); 00249 return true; 00250 } 00251 private: 00252 const double ax,ay,az,sx,sy,sz,xsp,ysp,zsp; 00253 const bool xperiodic,yperiodic,zperiodic; 00254 double px,py,pz,apx,apy,apz; 00255 double v0,v1,v2,v3,v4,v5; 00256 int ai,bi,aj,bj,ak,bk,s; 00257 int ci,cj,ck,di,dj,dk,inc1,inc2; 00258 inline int step_mod(int a,int b) {return a>=0?a%b:b-1-(b-1-a)%b;} 00259 inline int step_div(int a,int b) {return a>=0?a/b:-1+(a+1)/b;} 00260 inline int step_int(double a) {return a<0?int(a)-1:int(a);} 00261 void setup_common(); 00262 bool next_block(); 00263 bool out_of_bounds(); 00264 }; 00265 00266 /** \brief Class for looping over all of the particles specified in a 00267 * pre-assembled particle_order class. 00268 * 00269 * The particle_order class can be used to create a specific order of particles 00270 * within the container. This class can then loop over these particles in this 00271 * order. The class is particularly useful in cases where the ordering of the 00272 * output must match the ordering of particles as they were inserted into the 00273 * container. */ 00274 class c_loop_order : public c_loop_base { 00275 public: 00276 /** A reference to the ordering class to use. */ 00277 particle_order &vo; 00278 /** A pointer to the current position in the ordering class. */ 00279 int *cp; 00280 /** A pointer to the end position in the ordering class. */ 00281 int *op; 00282 /** The constructor copies several necessary constants from the 00283 * base class, and sets up a reference to the ordering class to 00284 * use. 00285 * \param[in] con the container class to use. 00286 * \param[in] vo_ the ordering class to use. */ 00287 template<class c_class> 00288 c_loop_order(c_class &con,particle_order &vo_) 00289 : c_loop_base(con), vo(vo_), nx(con.nx), nxy(con.nxy) {} 00290 /** Sets the class to consider the first particle. 00291 * \return True if there is any particle to consider, false 00292 * otherwise. */ 00293 inline bool start() { 00294 cp=vo.o;op=vo.op; 00295 if(cp!=op) { 00296 ijk=*(cp++);decode(); 00297 q=*(cp++); 00298 return true; 00299 } else return false; 00300 } 00301 /** Finds the next particle to test. 00302 * \return True if there is another particle, false if no more 00303 * particles are available. */ 00304 inline bool inc() { 00305 if(cp==op) return false; 00306 ijk=*(cp++);decode(); 00307 q=*(cp++); 00308 return true; 00309 } 00310 private: 00311 /** The number of computational blocks in the x direction. */ 00312 const int nx; 00313 /** The number of computational blocks in a z-slice. */ 00314 const int nxy; 00315 /** Takes the current block index and computes indices in the 00316 * x, y, and z directions. */ 00317 inline void decode() { 00318 k=ijk/nxy; 00319 int ijkt=ijk-nxy*k; 00320 j=ijkt/nx; 00321 i=ijkt-j*nx; 00322 } 00323 }; 00324 00325 /** \brief A class for looping over all particles in a container_periodic or 00326 * container_periodic_poly class. 00327 * 00328 * Since the container_periodic and container_periodic_poly classes have a 00329 * fundamentally different memory organization, the regular loop classes cannot 00330 * be used with them. */ 00331 class c_loop_all_periodic : public c_loop_base { 00332 public: 00333 /** The constructor copies several necessary constants from the 00334 * base periodic container class. 00335 * \param[in] con the periodic container class to use. */ 00336 template<class c_class> 00337 c_loop_all_periodic(c_class &con) : c_loop_base(con), ey(con.ey), ez(con.ez), wy(con.wy), wz(con.wz), 00338 ijk0(nx*(ey+con.oy*ez)), inc2(2*nx*con.ey+1) {} 00339 /** Sets the class to consider the first particle. 00340 * \return True if there is any particle to consider, false 00341 * otherwise. */ 00342 inline bool start() { 00343 i=0; 00344 j=ey; 00345 k=ez; 00346 ijk=ijk0; 00347 q=0; 00348 while(co[ijk]==0) if(!next_block()) return false; 00349 return true; 00350 } 00351 /** Finds the next particle to test. 00352 * \return True if there is another particle, false if no more 00353 * particles are available. */ 00354 inline bool inc() { 00355 q++; 00356 if(q>=co[ijk]) { 00357 q=0; 00358 do { 00359 if(!next_block()) return false; 00360 } while(co[ijk]==0); 00361 } 00362 return true; 00363 } 00364 private: 00365 /** The lower y index (inclusive) of the primary domain within 00366 * the block structure. */ 00367 int ey; 00368 /** The lower y index (inclusive) of the primary domain within 00369 * the block structure. */ 00370 int ez; 00371 /** The upper y index (exclusive) of the primary domain within 00372 * the block structure. */ 00373 int wy; 00374 /** The upper z index (exclusive) of the primary domain within 00375 * the block structure. */ 00376 int wz; 00377 /** The index of the (0,0,0) block within the block structure. 00378 */ 00379 int ijk0; 00380 /** A value to increase ijk by when the z index is increased. 00381 */ 00382 int inc2; 00383 /** Updates the internal variables to find the next 00384 * computational block with any particles. 00385 * \return True if another block is found, false if there are 00386 * no more blocks. */ 00387 inline bool next_block() { 00388 i++; 00389 if(i==nx) { 00390 i=0;j++; 00391 if(j==wy) { 00392 j=ey;k++; 00393 if(k==wz) return false; 00394 ijk+=inc2; 00395 } else ijk++; 00396 } else ijk++; 00397 return true; 00398 } 00399 }; 00400 00401 /** \brief Class for looping over all of the particles specified in a 00402 * pre-assembled particle_order class, for use with container_periodic classes. 00403 * 00404 * The particle_order class can be used to create a specific order of particles 00405 * within the container. This class can then loop over these particles in this 00406 * order. The class is particularly useful in cases where the ordering of the 00407 * output must match the ordering of particles as they were inserted into the 00408 * container. */ 00409 class c_loop_order_periodic : public c_loop_base { 00410 public: 00411 /** A reference to the ordering class to use. */ 00412 particle_order &vo; 00413 /** A pointer to the current position in the ordering class. */ 00414 int *cp; 00415 /** A pointer to the end position in the ordering class. */ 00416 int *op; 00417 /** The constructor copies several necessary constants from the 00418 * base class, and sets up a reference to the ordering class to 00419 * use. 00420 * \param[in] con the container class to use. 00421 * \param[in] vo_ the ordering class to use. */ 00422 template<class c_class> 00423 c_loop_order_periodic(c_class &con,particle_order &vo_) 00424 : c_loop_base(con), vo(vo_), nx(con.nx), oxy(con.nx*con.oy) {} 00425 /** Sets the class to consider the first particle. 00426 * \return True if there is any particle to consider, false 00427 * otherwise. */ 00428 inline bool start() { 00429 cp=vo.o;op=vo.op; 00430 if(cp!=op) { 00431 ijk=*(cp++);decode(); 00432 q=*(cp++); 00433 return true; 00434 } else return false; 00435 } 00436 /** Finds the next particle to test. 00437 * \return True if there is another particle, false if no more 00438 * particles are available. */ 00439 inline bool inc() { 00440 if(cp==op) return false; 00441 ijk=*(cp++);decode(); 00442 q=*(cp++); 00443 return true; 00444 } 00445 private: 00446 /** The number of computational blocks in the x direction. */ 00447 const int nx; 00448 /** The number of computational blocks in a z-slice. */ 00449 const int oxy; 00450 /** Takes the current block index and computes indices in the 00451 * x, y, and z directions. */ 00452 inline void decode() { 00453 k=ijk/oxy; 00454 int ijkt=ijk-oxy*k; 00455 j=ijkt/nx; 00456 i=ijkt-j*nx; 00457 } 00458 }; 00459 00460 } 00461 00462 #endif