Voro++
c_loops.cc
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.cc
00008  * \brief Function implementations for the loop classes. */
00009 
00010 #include "c_loops.hh"
00011 
00012 namespace voro {
00013 
00014 /** Initializes a c_loop_subset object to scan over all particles within a
00015  * given sphere.
00016  * \param[in] (vx,vy,vz) the position vector of the center of the sphere.
00017  * \param[in] r the radius of the sphere.
00018  * \param[in] bounds_test whether to do detailed bounds checking. If this is
00019  *                        false then the class will loop over all particles in
00020  *                        blocks that overlap the given sphere. If it is true,
00021  *                        the particle will only loop over the particles which
00022  *                        actually lie within the sphere.
00023  * \return True if there is any valid point to loop over, false otherwise. */
00024 void c_loop_subset::setup_sphere(double vx,double vy,double vz,double r,bool bounds_test) {
00025         if(bounds_test) {mode=sphere;v0=vx;v1=vy;v2=vz;v3=r*r;} else mode=no_check;
00026         ai=step_int((vx-ax-r)*xsp);
00027         bi=step_int((vx-ax+r)*xsp);
00028         aj=step_int((vy-ay-r)*ysp);
00029         bj=step_int((vy-ay+r)*ysp);
00030         ak=step_int((vz-az-r)*zsp);
00031         bk=step_int((vz-az+r)*zsp);
00032         setup_common();
00033 }
00034 
00035 /** Initializes the class to loop over all particles in a rectangular subgrid
00036  * of blocks.
00037  * \param[in] (ai_,bi_) the subgrid range in the x-direction, inclusive of both
00038  *                      ends.
00039  * \param[in] (aj_,bj_) the subgrid range in the y-direction, inclusive of both
00040  *                      ends.
00041  * \param[in] (ak_,bk_) the subgrid range in the z-direction, inclusive of both
00042  *                      ends.
00043  * \return True if there is any valid point to loop over, false otherwise. */
00044 void c_loop_subset::setup_intbox(int ai_,int bi_,int aj_,int bj_,int ak_,int bk_) {
00045         ai=ai_;bi=bi_;aj=aj_;bj=bj_;ak=ak_;bk=bk_;
00046         mode=no_check;
00047         setup_common();
00048 }
00049 
00050 /** Sets up all of the common constants used for the loop.
00051  * \return True if there is any valid point to loop over, false otherwise. */
00052 void c_loop_subset::setup_common() {
00053         if(!xperiodic) {
00054                 if(ai<0) {ai=0;if(bi<0) bi=0;}
00055                 if(bi>=nx) {bi=nx-1;if(ai>=nx) ai=nx-1;}
00056         }
00057         if(!yperiodic) {
00058                 if(aj<0) {aj=0;if(bj<0) bj=0;}
00059                 if(bj>=ny) {bj=ny-1;if(aj>=ny) aj=ny-1;}
00060         }
00061         if(!zperiodic) {
00062                 if(ak<0) {ak=0;if(bk<0) bk=0;}
00063                 if(bk>=nz) {bk=nz-1;if(ak>=nz) ak=nz-1;}
00064         }
00065         ci=ai;cj=aj;ck=ak;
00066         di=i=step_mod(ci,nx);apx=px=step_div(ci,nx)*sx;
00067         dj=j=step_mod(cj,ny);apy=py=step_div(cj,ny)*sy;
00068         dk=k=step_mod(ck,nz);apz=pz=step_div(ck,nz)*sz;
00069         inc1=di-step_mod(bi,nx);
00070         inc2=nx*(ny+dj-step_mod(bj,ny))+inc1;
00071         inc1+=nx;
00072         ijk=di+nx*(dj+ny*dk);
00073         q=0;
00074 }
00075 
00076 /** Starts the loop by finding the first particle within the container to
00077  * consider.
00078  * \return True if there is any particle to consider, false otherwise. */
00079 bool c_loop_subset::start() {
00080         while(co[ijk]==0) {if(!next_block()) return false;}
00081         while(mode!=no_check&&out_of_bounds()) {
00082                 q++;
00083                 while(q>=co[ijk]) {q=0;if(!next_block()) return false;}
00084         }
00085         return true;
00086 }
00087 
00088 /** Initializes the class to loop over all particles in a rectangular box.
00089  * \param[in] (xmin,xmax) the minimum and maximum x coordinates of the box.
00090  * \param[in] (ymin,ymax) the minimum and maximum y coordinates of the box.
00091  * \param[in] (zmin,zmax) the minimum and maximum z coordinates of the box.
00092  * \param[in] bounds_test whether to do detailed bounds checking. If this is
00093  *                        false then the class will loop over all particles in
00094  *                        blocks that overlap the given box. If it is true, the
00095  *                        particle will only loop over the particles which
00096  *                        actually lie within the box.
00097  * \return True if there is any valid point to loop over, false otherwise. */
00098 void c_loop_subset::setup_box(double xmin,double xmax,double ymin,double ymax,double zmin,double zmax,bool bounds_test) {
00099         if(bounds_test) {mode=box;v0=xmin;v1=xmax;v2=ymin;v3=ymax;v4=zmin;v5=zmax;} else mode=no_check;
00100         ai=step_int((xmin-ax)*xsp);
00101         bi=step_int((xmax-ax)*xsp);
00102         aj=step_int((ymin-ay)*ysp);
00103         bj=step_int((ymax-ay)*ysp);
00104         ak=step_int((zmin-az)*zsp);
00105         bk=step_int((zmax-az)*zsp);
00106         setup_common();
00107 }
00108 
00109 /** Computes whether the current point is out of bounds, relative to the
00110  * current loop setup.
00111  * \return True if the point is out of bounds, false otherwise. */
00112 bool c_loop_subset::out_of_bounds() {
00113         double *pp=p[ijk]+ps*q;
00114         if(mode==sphere) {
00115                 double fx(*pp+px-v0),fy(pp[1]+py-v1),fz(pp[2]+pz-v2);
00116                 return fx*fx+fy*fy+fz*fz>v3;
00117         } else {
00118                 double f(*pp+px);if(f<v0||f>v1) return true;
00119                 f=pp[1]+py;if(f<v2||f>v3) return true;
00120                 f=pp[2]+pz;return f<v4||f>v5;
00121         }
00122 }
00123 
00124 /** Returns the next block to be tested in a loop, and updates the periodicity
00125  * vector if necessary. */
00126 bool c_loop_subset::next_block() {
00127         if(i<bi) {
00128                 i++;
00129                 if(ci<nx-1) {ci++;ijk++;} else {ci=0;ijk+=1-nx;px+=sx;}
00130                 return true;
00131         } else if(j<bj) {
00132                 i=ai;ci=di;px=apx;j++;
00133                 if(cj<ny-1) {cj++;ijk+=inc1;} else {cj=0;ijk+=inc1-nxy;py+=sy;}
00134                 return true;
00135         } else if(k<bk) {
00136                 i=ai;ci=di;j=aj;cj=dj;px=apx;py=apy;k++;
00137                 if(ck<nz-1) {ck++;ijk+=inc2;} else {ck=0;ijk+=inc2-nxyz;pz+=sz;}
00138                 return true;
00139         } else return false;
00140 }
00141 
00142 /** Extends the memory available for storing the ordering. */
00143 void particle_order::add_ordering_memory() {
00144         int *no=new int[size<<2],*nop=no,*opp=o;
00145         while(opp<op) *(nop++)=*(opp++);
00146         delete [] o;
00147         size<<=1;o=no;op=nop;
00148 }
00149 
00150 }