Voro++
c_loops.hh
Go to the documentation of this file.
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_V_LOOPS_HH
00011 #define VOROPP_V_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 double 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                 template<class c_class>
00174                 /** The constructor copies several necessary constants from the
00175                  * base container class.
00176                  * \param[in] con the container class to use. */
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 }
00402 
00403 #endif