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 v_compute.cc 00008 * \brief Function implementantions for the v_compute class. */ 00009 00010 #include "worklist.hh" 00011 #include "v_compute.hh" 00012 #include "container.hh" 00013 #include "container_prd.hh" 00014 00015 namespace voro { 00016 00017 /** The class constructor initializes constants from the container class, and 00018 * sets up the mask and queue used for Voronoi computations. 00019 * \param[in] con_ a reference to the container class to use. 00020 * \param[in] (hx_,hy_,hz_) the size of the mask to use. */ 00021 template<class c_class> 00022 voro_compute<c_class>::voro_compute(c_class &con_,int hx_,int hy_,int hz_) : 00023 con(con_), boxx(con_.boxx), boxy(con_.boxy), boxz(con_.boxz), 00024 xsp(con_.xsp), ysp(con_.ysp), zsp(con_.zsp), 00025 hx(hx_), hy(hy_), hz(hz_), hxy(hx_*hy_), hxyz(hxy*hz_), ps(con_.ps), 00026 id(con_.id), p(con_.p), co(con_.co), bxsq(boxx*boxx+boxy*boxy+boxz*boxz), 00027 mv(0), qu_size(3*(3+hxy+hz*(hx+hy))), wl(con_.wl), mrad(con_.mrad), 00028 mask(new unsigned int[hxyz]), qu(new int[qu_size]), qu_l(qu+qu_size) { 00029 reset_mask(); 00030 } 00031 00032 /** Scans all of the particles within a block to see if any of them have a 00033 * smaller distance to the given test vector. If one is found, the routine 00034 * updates the minimum distance and store information about this particle. 00035 * \param[in] ijk the index of the block. 00036 * \param[in] (x,y,z) the test vector to consider (which may have already had a 00037 * periodic displacement applied to it). 00038 * \param[in] (di,dj,dk) 00039 * \param[in,out] w a reference to a particle record in which to store 00040 * information about the particle whose Voronoi cell the 00041 * vector is within. 00042 * \param[in,out] mrs the current minimum distance, that may be updated if a 00043 * closer particle is found. */ 00044 template<class c_class> 00045 inline void voro_compute<c_class>::scan_all(int ijk,double x,double y,double z,int di,int dj,int dk,particle_record &w,double &mrs) { 00046 double x1,y1,z1,rs;bool in_block=false; 00047 for(int l=0;l<co[ijk];l++) { 00048 x1=p[ijk][ps*l]-x; 00049 y1=p[ijk][ps*l+1]-y; 00050 z1=p[ijk][ps*l+2]-z; 00051 rs=con.r_current_sub(x1*x1+y1*y1+z1*z1,ijk,l); 00052 if(rs<mrs) {mrs=rs;w.l=l;in_block=true;} 00053 } 00054 if(in_block) {w.ijk=ijk;w.di=di;w.dj=dj,w.dk=dk;} 00055 } 00056 00057 /** Finds the Voronoi cell that given vector is within. For containers that are 00058 * not radially dependent, this corresponds to findig the particle that is 00059 * closest to the vector; for the radical tessellation containers, this 00060 * corresponds to a finding the minimum weighted distance. 00061 * \param[in] (x,y,z) the vector to consider. 00062 * \param[in] (ci,cj,ck) the coordinates of the block that the test particle is 00063 * in relative to the container data structure. 00064 * \param[in] ijk the index of the block that the test particle is in. 00065 * \param[out] w a reference to a particle record in which to store information 00066 * about the particle whose Voronoi cell the vector is within. 00067 * \param[out] mrs the minimum computed distance. */ 00068 template<class c_class> 00069 void voro_compute<c_class>::find_voronoi_cell(double x,double y,double z,int ci,int cj,int ck,int ijk,particle_record &w,double &mrs) { 00070 double qx=0,qy=0,qz=0,rs; 00071 int i,j,k,di,dj,dk,ei,ej,ek,f,g,disp; 00072 double fx,fy,fz,mxs,mys,mzs,*radp; 00073 unsigned int q,*e,*mijk; 00074 00075 // Init setup for parameters to return 00076 w.ijk=-1;mrs=large_number; 00077 00078 con.initialize_search(ci,cj,ck,ijk,i,j,k,disp); 00079 00080 // Test all particles in the particle's local region first 00081 scan_all(ijk,x,y,z,0,0,0,w,mrs); 00082 00083 // Now compute the fractional position of the particle within its 00084 // region and store it in (fx,fy,fz). We use this to compute an index 00085 // (di,dj,dk) of which subregion the particle is within. 00086 unsigned int m1,m2; 00087 con.frac_pos(x,y,z,ci,cj,ck,fx,fy,fz); 00088 di=int(fx*xsp*wl_fgrid);dj=int(fy*ysp*wl_fgrid);dk=int(fz*zsp*wl_fgrid); 00089 00090 // The indices (di,dj,dk) tell us which worklist to use, to test the 00091 // blocks in the optimal order. But we only store worklists for the 00092 // eighth of the region where di, dj, and dk are all less than half the 00093 // full grid. The rest of the cases are handled by symmetry. In this 00094 // section, we detect for these cases, by reflecting high values of di, 00095 // dj, and dk. For these cases, a mask is constructed in m1 and m2 00096 // which is used to flip the worklist information when it is loaded. 00097 if(di>=wl_hgrid) { 00098 mxs=boxx-fx; 00099 m1=127+(3<<21);m2=1+(1<<21);di=wl_fgrid-1-di;if(di<0) di=0; 00100 } else {m1=m2=0;mxs=fx;} 00101 if(dj>=wl_hgrid) { 00102 mys=boxy-fy; 00103 m1|=(127<<7)+(3<<24);m2|=(1<<7)+(1<<24);dj=wl_fgrid-1-dj;if(dj<0) dj=0; 00104 } else mys=fy; 00105 if(dk>=wl_hgrid) { 00106 mzs=boxz-fz; 00107 m1|=(127<<14)+(3<<27);m2|=(1<<14)+(1<<27);dk=wl_fgrid-1-dk;if(dk<0) dk=0; 00108 } else mzs=fz; 00109 00110 // Do a quick test to account for the case when the minimum radius is 00111 // small enought that no other blocks need to be considered 00112 rs=con.r_max_add(mrs); 00113 if(mxs*mxs>rs&&mys*mys>rs&&mzs*mzs>rs) return; 00114 00115 // Now compute which worklist we are going to use, and set radp and e to 00116 // point at the right offsets 00117 ijk=di+wl_hgrid*(dj+wl_hgrid*dk); 00118 radp=mrad+ijk*wl_seq_length; 00119 e=(const_cast<unsigned int*> (wl))+ijk*wl_seq_length; 00120 00121 // Read in how many items in the worklist can be tested without having to 00122 // worry about writing to the mask 00123 f=e[0];g=0; 00124 do { 00125 00126 // If mrs is less than the minimum distance to any untested 00127 // block, then we are done 00128 if(con.r_max_add(mrs)<radp[g]) return; 00129 g++; 00130 00131 // Load in a block off the worklist, permute it with the 00132 // symmetry mask, and decode its position. These are all 00133 // integer bit operations so they should run very fast. 00134 q=e[g];q^=m1;q+=m2; 00135 di=q&127;di-=64; 00136 dj=(q>>7)&127;dj-=64; 00137 dk=(q>>14)&127;dk-=64; 00138 00139 // Check that the worklist position is in range 00140 ei=di+i;if(ei<0||ei>=hx) continue; 00141 ej=dj+j;if(ej<0||ej>=hy) continue; 00142 ek=dk+k;if(ek<0||ek>=hz) continue; 00143 00144 // Call the compute_min_max_radius() function. This returns 00145 // true if the minimum distance to the block is bigger than the 00146 // current mrs, in which case we skip this block and move on. 00147 // Otherwise, it computes the maximum distance to the block and 00148 // returns it in crs. 00149 if(compute_min_radius(di,dj,dk,fx,fy,fz,mrs)) continue; 00150 00151 // Now compute which region we are going to loop over, adding a 00152 // displacement for the periodic cases 00153 ijk=con.region_index(ci,cj,ck,ei,ej,ek,qx,qy,qz,disp); 00154 00155 // If mrs is bigger than the maximum distance to the block, 00156 // then we have to test all particles in the block for 00157 // intersections. Otherwise, we do additional checks and skip 00158 // those particles which can't possibly intersect the block. 00159 scan_all(ijk,x-qx,y-qy,z-qz,di,dj,dk,w,mrs); 00160 } while(g<f); 00161 00162 // Update mask value and initialize queue 00163 mv++; 00164 if(mv==0) {reset_mask();mv=1;} 00165 int *qu_s=qu,*qu_e=qu; 00166 00167 while(g<wl_seq_length-1) { 00168 00169 // If mrs is less than the minimum distance to any untested 00170 // block, then we are done 00171 if(con.r_max_add(mrs)<radp[g]) return; 00172 g++; 00173 00174 // Load in a block off the worklist, permute it with the 00175 // symmetry mask, and decode its position. These are all 00176 // integer bit operations so they should run very fast. 00177 q=e[g];q^=m1;q+=m2; 00178 di=q&127;di-=64; 00179 dj=(q>>7)&127;dj-=64; 00180 dk=(q>>14)&127;dk-=64; 00181 00182 // Compute the position in the mask of the current block. If 00183 // this lies outside the mask, then skip it. Otherwise, mark 00184 // it. 00185 ei=di+i;if(ei<0||ei>=hx) continue; 00186 ej=dj+j;if(ej<0||ej>=hy) continue; 00187 ek=dk+k;if(ek<0||ek>=hz) continue; 00188 mijk=mask+ei+hx*(ej+hy*ek); 00189 *mijk=mv; 00190 00191 // Skip this block if it is further away than the current 00192 // minimum radius 00193 if(compute_min_radius(di,dj,dk,fx,fy,fz,mrs)) continue; 00194 00195 // Now compute which region we are going to loop over, adding a 00196 // displacement for the periodic cases 00197 ijk=con.region_index(ci,cj,ck,ei,ej,ek,qx,qy,qz,disp); 00198 scan_all(ijk,x-qx,y-qy,z-qz,di,dj,dk,w,mrs); 00199 00200 if(qu_e>qu_l-18) add_list_memory(qu_s,qu_e); 00201 scan_bits_mask_add(q,mijk,ei,ej,ek,qu_e); 00202 } 00203 00204 // Do a check to see if we've reached the radius cutoff 00205 if(con.r_max_add(mrs)<radp[g]) return; 00206 00207 // We were unable to completely compute the cell based on the blocks in 00208 // the worklist, so now we have to go block by block, reading in items 00209 // off the list 00210 while(qu_s!=qu_e) { 00211 00212 // Read the next entry of the queue 00213 if(qu_s==qu_l) qu_s=qu; 00214 ei=*(qu_s++);ej=*(qu_s++);ek=*(qu_s++); 00215 di=ei-i;dj=ej-j;dk=ek-k; 00216 if(compute_min_radius(di,dj,dk,fx,fy,fz,mrs)) continue; 00217 00218 ijk=con.region_index(ci,cj,ck,ei,ej,ek,qx,qy,qz,disp); 00219 scan_all(ijk,x-qx,y-qy,z-qz,di,dj,dk,w,mrs); 00220 00221 // Test the neighbors of the current block, and add them to the 00222 // block list if they haven't already been tested 00223 if((qu_s<=qu_e?(qu_l-qu_e)+(qu_s-qu):qu_s-qu_e)<18) add_list_memory(qu_s,qu_e); 00224 add_to_mask(ei,ej,ek,qu_e); 00225 } 00226 } 00227 00228 /** Scans the six orthogonal neighbors of a given block and adds them to the 00229 * queue if they haven't been considered already. It assumes that the queue 00230 * will definitely have enough memory to add six entries at the end. 00231 * \param[in] (ei,ej,ek) the block to consider. 00232 * \param[in,out] qu_e a pointer to the end of the queue. */ 00233 template<class c_class> 00234 inline void voro_compute<c_class>::add_to_mask(int ei,int ej,int ek,int *&qu_e) { 00235 unsigned int *mijk=mask+ei+hx*(ej+hy*ek); 00236 if(ek>0) if(*(mijk-hxy)!=mv) {if(qu_e==qu_l) qu_e=qu;*(mijk-hxy)=mv;*(qu_e++)=ei;*(qu_e++)=ej;*(qu_e++)=ek-1;} 00237 if(ej>0) if(*(mijk-hx)!=mv) {if(qu_e==qu_l) qu_e=qu;*(mijk-hx)=mv;*(qu_e++)=ei;*(qu_e++)=ej-1;*(qu_e++)=ek;} 00238 if(ei>0) if(*(mijk-1)!=mv) {if(qu_e==qu_l) qu_e=qu;*(mijk-1)=mv;*(qu_e++)=ei-1;*(qu_e++)=ej;*(qu_e++)=ek;} 00239 if(ei<hx-1) if(*(mijk+1)!=mv) {if(qu_e==qu_l) qu_e=qu;*(mijk+1)=mv;*(qu_e++)=ei+1;*(qu_e++)=ej;*(qu_e++)=ek;} 00240 if(ej<hy-1) if(*(mijk+hx)!=mv) {if(qu_e==qu_l) qu_e=qu;*(mijk+hx)=mv;*(qu_e++)=ei;*(qu_e++)=ej+1;*(qu_e++)=ek;} 00241 if(ek<hz-1) if(*(mijk+hxy)!=mv) {if(qu_e==qu_l) qu_e=qu;*(mijk+hxy)=mv;*(qu_e++)=ei;*(qu_e++)=ej;*(qu_e++)=ek+1;} 00242 } 00243 00244 /** Scans a worklist entry and adds any blocks to the queue 00245 * \param[in] (ei,ej,ek) the block to consider. 00246 * \param[in,out] qu_e a pointer to the end of the queue. */ 00247 template<class c_class> 00248 inline void voro_compute<c_class>::scan_bits_mask_add(unsigned int q,unsigned int *mijk,int ei,int ej,int ek,int *&qu_e) { 00249 const unsigned int b1=1<<21,b2=1<<22,b3=1<<24,b4=1<<25,b5=1<<27,b6=1<<28; 00250 if((q&b2)==b2) { 00251 if(ei>0) {*(mijk-1)=mv;*(qu_e++)=ei-1;*(qu_e++)=ej;*(qu_e++)=ek;} 00252 if((q&b1)==0&&ei<hx-1) {*(mijk+1)=mv;*(qu_e++)=ei+1;*(qu_e++)=ej;*(qu_e++)=ek;} 00253 } else if((q&b1)==b1&&ei<hx-1) {*(mijk+1)=mv;*(qu_e++)=ei+1;*(qu_e++)=ej;*(qu_e++)=ek;} 00254 if((q&b4)==b4) { 00255 if(ej>0) {*(mijk-hx)=mv;*(qu_e++)=ei;*(qu_e++)=ej-1;*(qu_e++)=ek;} 00256 if((q&b3)==0&&ej<hy-1) {*(mijk+hx)=mv;*(qu_e++)=ei;*(qu_e++)=ej+1;*(qu_e++)=ek;} 00257 } else if((q&b3)==b3&&ej<hy-1) {*(mijk+hx)=mv;*(qu_e++)=ei;*(qu_e++)=ej+1;*(qu_e++)=ek;} 00258 if((q&b6)==b6) { 00259 if(ek>0) {*(mijk-hxy)=mv;*(qu_e++)=ei;*(qu_e++)=ej;*(qu_e++)=ek-1;} 00260 if((q&b5)==0&&ek<hz-1) {*(mijk+hxy)=mv;*(qu_e++)=ei;*(qu_e++)=ej;*(qu_e++)=ek+1;} 00261 } else if((q&b5)==b5&&ek<hz-1) {*(mijk+hxy)=mv;*(qu_e++)=ei;*(qu_e++)=ej;*(qu_e++)=ek+1;} 00262 } 00263 00264 /** This routine computes a Voronoi cell for a single particle in the 00265 * container. It can be called by the user, but is also forms the core part of 00266 * several of the main functions, such as store_cell_volumes(), print_all(), 00267 * and the drawing routines. The algorithm constructs the cell by testing over 00268 * the neighbors of the particle, working outwards until it reaches those 00269 * particles which could not possibly intersect the cell. For maximum 00270 * efficiency, this algorithm is divided into three parts. In the first 00271 * section, the algorithm tests over the blocks which are in the immediate 00272 * vicinity of the particle, by making use of one of the precomputed worklists. 00273 * The code then continues to test blocks on the worklist, but also begins to 00274 * construct a list of neighboring blocks outside the worklist which may need 00275 * to be test. In the third section, the routine starts testing these 00276 * neighboring blocks, evaluating whether or not a particle in them could 00277 * possibly intersect the cell. For blocks that intersect the cell, it tests 00278 * the particles in that block, and then adds the block neighbors to the list 00279 * of potential places to consider. 00280 * \param[in,out] c a reference to a voronoicell object. 00281 * \param[in] ijk the index of the block that the test particle is in. 00282 * \param[in] s the index of the particle within the test block. 00283 * \param[in] (ci,cj,ck) the coordinates of the block that the test particle is 00284 * in relative to the container data structure. 00285 * \return False if the Voronoi cell was completely removed during the 00286 * computation and has zero volume, true otherwise. */ 00287 template<class c_class> 00288 template<class v_cell> 00289 bool voro_compute<c_class>::compute_cell(v_cell &c,int ijk,int s,int ci,int cj,int ck) { 00290 static const int count_list[8]={7,11,15,19,26,35,45,59},*count_e=count_list+8; 00291 double x,y,z,x1,y1,z1,qx=0,qy=0,qz=0; 00292 double xlo,ylo,zlo,xhi,yhi,zhi,x2,y2,z2,rs; 00293 int i,j,k,di,dj,dk,ei,ej,ek,f,g,l,disp; 00294 double fx,fy,fz,gxs,gys,gzs,*radp; 00295 unsigned int q,*e,*mijk; 00296 00297 if(!con.initialize_voronoicell(c,ijk,s,ci,cj,ck,i,j,k,x,y,z,disp)) return false; 00298 con.r_init(ijk,s); 00299 00300 // Initialize the Voronoi cell to fill the entire container 00301 double crs,mrs; 00302 00303 int next_count=3,*count_p=(const_cast<int*> (count_list)); 00304 00305 // Test all particles in the particle's local region first 00306 for(l=0;l<s;l++) { 00307 x1=p[ijk][ps*l]-x; 00308 y1=p[ijk][ps*l+1]-y; 00309 z1=p[ijk][ps*l+2]-z; 00310 rs=con.r_scale(x1*x1+y1*y1+z1*z1,ijk,l); 00311 if(!c.nplane(x1,y1,z1,rs,id[ijk][l])) return false; 00312 } 00313 l++; 00314 while(l<co[ijk]) { 00315 x1=p[ijk][ps*l]-x; 00316 y1=p[ijk][ps*l+1]-y; 00317 z1=p[ijk][ps*l+2]-z; 00318 rs=con.r_scale(x1*x1+y1*y1+z1*z1,ijk,l); 00319 if(!c.nplane(x1,y1,z1,rs,id[ijk][l])) return false; 00320 l++; 00321 } 00322 00323 // Now compute the maximum distance squared from the cell center to a 00324 // vertex. This is used to cut off the calculation since we only need 00325 // to test out to twice this range. 00326 mrs=c.max_radius_squared(); 00327 00328 // Now compute the fractional position of the particle within its 00329 // region and store it in (fx,fy,fz). We use this to compute an index 00330 // (di,dj,dk) of which subregion the particle is within. 00331 unsigned int m1,m2; 00332 con.frac_pos(x,y,z,ci,cj,ck,fx,fy,fz); 00333 di=int(fx*xsp*wl_fgrid);dj=int(fy*ysp*wl_fgrid);dk=int(fz*zsp*wl_fgrid); 00334 00335 // The indices (di,dj,dk) tell us which worklist to use, to test the 00336 // blocks in the optimal order. But we only store worklists for the 00337 // eighth of the region where di, dj, and dk are all less than half the 00338 // full grid. The rest of the cases are handled by symmetry. In this 00339 // section, we detect for these cases, by reflecting high values of di, 00340 // dj, and dk. For these cases, a mask is constructed in m1 and m2 00341 // which is used to flip the worklist information when it is loaded. 00342 if(di>=wl_hgrid) { 00343 gxs=fx; 00344 m1=127+(3<<21);m2=1+(1<<21);di=wl_fgrid-1-di;if(di<0) di=0; 00345 } else {m1=m2=0;gxs=boxx-fx;} 00346 if(dj>=wl_hgrid) { 00347 gys=fy; 00348 m1|=(127<<7)+(3<<24);m2|=(1<<7)+(1<<24);dj=wl_fgrid-1-dj;if(dj<0) dj=0; 00349 } else gys=boxy-fy; 00350 if(dk>=wl_hgrid) { 00351 gzs=fz; 00352 m1|=(127<<14)+(3<<27);m2|=(1<<14)+(1<<27);dk=wl_fgrid-1-dk;if(dk<0) dk=0; 00353 } else gzs=boxz-fz; 00354 gxs*=gxs;gys*=gys;gzs*=gzs; 00355 00356 // Now compute which worklist we are going to use, and set radp and e to 00357 // point at the right offsets 00358 ijk=di+wl_hgrid*(dj+wl_hgrid*dk); 00359 radp=mrad+ijk*wl_seq_length; 00360 e=(const_cast<unsigned int*> (wl))+ijk*wl_seq_length; 00361 00362 // Read in how many items in the worklist can be tested without having to 00363 // worry about writing to the mask 00364 f=e[0];g=0; 00365 do { 00366 00367 // At the intervals specified by count_list, we recompute the 00368 // maximum radius squared 00369 if(g==next_count) { 00370 mrs=c.max_radius_squared(); 00371 if(count_p!=count_e) next_count=*(count_p++); 00372 } 00373 00374 // If mrs is less than the minimum distance to any untested 00375 // block, then we are done 00376 if(mrs<con.r_cutoff(radp[g])) return true; 00377 g++; 00378 00379 // Load in a block off the worklist, permute it with the 00380 // symmetry mask, and decode its position. These are all 00381 // integer bit operations so they should run very fast. 00382 q=e[g];q^=m1;q+=m2; 00383 di=q&127;di-=64; 00384 dj=(q>>7)&127;dj-=64; 00385 dk=(q>>14)&127;dk-=64; 00386 00387 // Check that the worklist position is in range 00388 ei=di+i;if(ei<0||ei>=hx) continue; 00389 ej=dj+j;if(ej<0||ej>=hy) continue; 00390 ek=dk+k;if(ek<0||ek>=hz) continue; 00391 00392 // Call the compute_min_max_radius() function. This returns 00393 // true if the minimum distance to the block is bigger than the 00394 // current mrs, in which case we skip this block and move on. 00395 // Otherwise, it computes the maximum distance to the block and 00396 // returns it in crs. 00397 if(compute_min_max_radius(di,dj,dk,fx,fy,fz,gxs,gys,gzs,crs,mrs)) continue; 00398 00399 // Now compute which region we are going to loop over, adding a 00400 // displacement for the periodic cases 00401 ijk=con.region_index(ci,cj,ck,ei,ej,ek,qx,qy,qz,disp); 00402 00403 // If mrs is bigger than the maximum distance to the block, 00404 // then we have to test all particles in the block for 00405 // intersections. Otherwise, we do additional checks and skip 00406 // those particles which can't possibly intersect the block. 00407 if(co[ijk]>0) { 00408 l=0;x2=x-qx;y2=y-qy;z2=z-qz; 00409 if(mrs>con.r_cutoff(crs)) { 00410 do { 00411 x1=p[ijk][ps*l]-x2; 00412 y1=p[ijk][ps*l+1]-y2; 00413 z1=p[ijk][ps*l+2]-z2; 00414 rs=con.r_scale(x1*x1+y1*y1+z1*z1,ijk,l); 00415 if(!c.nplane(x1,y1,z1,rs,id[ijk][l])) return false; 00416 l++; 00417 } while (l<co[ijk]); 00418 } else { 00419 do { 00420 x1=p[ijk][ps*l]-x2; 00421 y1=p[ijk][ps*l+1]-y2; 00422 z1=p[ijk][ps*l+2]-z2; 00423 rs=con.r_scale(x1*x1+y1*y1+z1*z1,ijk,l); 00424 if(rs<mrs&&!c.nplane(x1,y1,z1,rs,id[ijk][l])) return false; 00425 l++; 00426 } while (l<co[ijk]); 00427 } 00428 } 00429 } while(g<f); 00430 00431 // If we reach here, we were unable to compute the entire cell using 00432 // the first part of the worklist. This section of the algorithm 00433 // continues the worklist, but it now starts preparing the mask that we 00434 // need if we end up going block by block. We do the same as before, 00435 // but we put a mark down on the mask for every block that's tested. 00436 // The worklist also contains information about which neighbors of each 00437 // block are not also on the worklist, and we start storing those 00438 // points in a list in case we have to go block by block. Update the 00439 // mask counter, and if it wraps around then reset the whole mask; that 00440 // will only happen once every 2^32 tries. 00441 mv++; 00442 if(mv==0) {reset_mask();mv=1;} 00443 00444 // Set the queue pointers 00445 int *qu_s=qu,*qu_e=qu; 00446 00447 while(g<wl_seq_length-1) { 00448 00449 // At the intervals specified by count_list, we recompute the 00450 // maximum radius squared 00451 if(g==next_count) { 00452 mrs=c.max_radius_squared(); 00453 if(count_p!=count_e) next_count=*(count_p++); 00454 } 00455 00456 // If mrs is less than the minimum distance to any untested 00457 // block, then we are done 00458 if(mrs<con.r_cutoff(radp[g])) return true; 00459 g++; 00460 00461 // Load in a block off the worklist, permute it with the 00462 // symmetry mask, and decode its position. These are all 00463 // integer bit operations so they should run very fast. 00464 q=e[g];q^=m1;q+=m2; 00465 di=q&127;di-=64; 00466 dj=(q>>7)&127;dj-=64; 00467 dk=(q>>14)&127;dk-=64; 00468 00469 // Compute the position in the mask of the current block. If 00470 // this lies outside the mask, then skip it. Otherwise, mark 00471 // it. 00472 ei=di+i;if(ei<0||ei>=hx) continue; 00473 ej=dj+j;if(ej<0||ej>=hy) continue; 00474 ek=dk+k;if(ek<0||ek>=hz) continue; 00475 mijk=mask+ei+hx*(ej+hy*ek); 00476 *mijk=mv; 00477 00478 // Call the compute_min_max_radius() function. This returns 00479 // true if the minimum distance to the block is bigger than the 00480 // current mrs, in which case we skip this block and move on. 00481 // Otherwise, it computes the maximum distance to the block and 00482 // returns it in crs. 00483 if(compute_min_max_radius(di,dj,dk,fx,fy,fz,gxs,gys,gzs,crs,mrs)) continue; 00484 00485 // Now compute which region we are going to loop over, adding a 00486 // displacement for the periodic cases 00487 ijk=con.region_index(ci,cj,ck,ei,ej,ek,qx,qy,qz,disp); 00488 00489 // If mrs is bigger than the maximum distance to the block, 00490 // then we have to test all particles in the block for 00491 // intersections. Otherwise, we do additional checks and skip 00492 // those particles which can't possibly intersect the block. 00493 if(co[ijk]>0) { 00494 l=0;x2=x-qx;y2=y-qy;z2=z-qz; 00495 if(mrs>con.r_cutoff(crs)) { 00496 do { 00497 x1=p[ijk][ps*l]-x2; 00498 y1=p[ijk][ps*l+1]-y2; 00499 z1=p[ijk][ps*l+2]-z2; 00500 rs=con.r_scale(x1*x1+y1*y1+z1*z1,ijk,l); 00501 if(!c.nplane(x1,y1,z1,rs,id[ijk][l])) return false; 00502 l++; 00503 } while (l<co[ijk]); 00504 } else { 00505 do { 00506 x1=p[ijk][ps*l]-x2; 00507 y1=p[ijk][ps*l+1]-y2; 00508 z1=p[ijk][ps*l+2]-z2; 00509 rs=con.r_scale(x1*x1+y1*y1+z1*z1,ijk,l); 00510 if(rs<mrs&&!c.nplane(x1,y1,z1,rs,id[ijk][l])) return false; 00511 l++; 00512 } while (l<co[ijk]); 00513 } 00514 } 00515 00516 // If there might not be enough memory on the list for these 00517 // additions, then add more 00518 if(qu_e>qu_l-18) add_list_memory(qu_s,qu_e); 00519 00520 // Test the parts of the worklist element which tell us what 00521 // neighbors of this block are not on the worklist. Store them 00522 // on the block list, and mark the mask. 00523 scan_bits_mask_add(q,mijk,ei,ej,ek,qu_e); 00524 } 00525 00526 // Do a check to see if we've reached the radius cutoff 00527 if(mrs<con.r_cutoff(radp[g])) return true; 00528 00529 // We were unable to completely compute the cell based on the blocks in 00530 // the worklist, so now we have to go block by block, reading in items 00531 // off the list 00532 while(qu_s!=qu_e) { 00533 00534 // If we reached the end of the list memory loop back to the 00535 // start 00536 if(qu_s==qu_l) qu_s=qu; 00537 00538 // Read in a block off the list, and compute the upper and lower 00539 // coordinates in each of the three dimensions 00540 ei=*(qu_s++);ej=*(qu_s++);ek=*(qu_s++); 00541 xlo=(ei-i)*boxx-fx;xhi=xlo+boxx; 00542 ylo=(ej-j)*boxy-fy;yhi=ylo+boxy; 00543 zlo=(ek-k)*boxz-fz;zhi=zlo+boxz; 00544 00545 // Carry out plane tests to see if any particle in this block 00546 // could possibly intersect the cell 00547 if(ei>i) { 00548 if(ej>j) { 00549 if(ek>k) {if(corner_test(c,xlo,ylo,zlo,xhi,yhi,zhi)) continue;} 00550 else if(ek<k) {if(corner_test(c,xlo,ylo,zhi,xhi,yhi,zlo)) continue;} 00551 else {if(edge_z_test(c,xlo,ylo,zlo,xhi,yhi,zhi)) continue;} 00552 } else if(ej<j) { 00553 if(ek>k) {if(corner_test(c,xlo,yhi,zlo,xhi,ylo,zhi)) continue;} 00554 else if(ek<k) {if(corner_test(c,xlo,yhi,zhi,xhi,ylo,zlo)) continue;} 00555 else {if(edge_z_test(c,xlo,yhi,zlo,xhi,ylo,zhi)) continue;} 00556 } else { 00557 if(ek>k) {if(edge_y_test(c,xlo,ylo,zlo,xhi,yhi,zhi)) continue;} 00558 else if(ek<k) {if(edge_y_test(c,xlo,ylo,zhi,xhi,yhi,zlo)) continue;} 00559 else {if(face_x_test(c,xlo,ylo,zlo,yhi,zhi)) continue;} 00560 } 00561 } else if(ei<i) { 00562 if(ej>j) { 00563 if(ek>k) {if(corner_test(c,xhi,ylo,zlo,xlo,yhi,zhi)) continue;} 00564 else if(ek<k) {if(corner_test(c,xhi,ylo,zhi,xlo,yhi,zlo)) continue;} 00565 else {if(edge_z_test(c,xhi,ylo,zlo,xlo,yhi,zhi)) continue;} 00566 } else if(ej<j) { 00567 if(ek>k) {if(corner_test(c,xhi,yhi,zlo,xlo,ylo,zhi)) continue;} 00568 else if(ek<k) {if(corner_test(c,xhi,yhi,zhi,xlo,ylo,zlo)) continue;} 00569 else {if(edge_z_test(c,xhi,yhi,zlo,xlo,ylo,zhi)) continue;} 00570 } else { 00571 if(ek>k) {if(edge_y_test(c,xhi,ylo,zlo,xlo,yhi,zhi)) continue;} 00572 else if(ek<k) {if(edge_y_test(c,xhi,ylo,zhi,xlo,yhi,zlo)) continue;} 00573 else {if(face_x_test(c,xhi,ylo,zlo,yhi,zhi)) continue;} 00574 } 00575 } else { 00576 if(ej>j) { 00577 if(ek>k) {if(edge_x_test(c,xlo,ylo,zlo,xhi,yhi,zhi)) continue;} 00578 else if(ek<k) {if(edge_x_test(c,xlo,ylo,zhi,xhi,yhi,zlo)) continue;} 00579 else {if(face_y_test(c,xlo,ylo,zlo,xhi,zhi)) continue;} 00580 } else if(ej<j) { 00581 if(ek>k) {if(edge_x_test(c,xlo,yhi,zlo,xhi,ylo,zhi)) continue;} 00582 else if(ek<k) {if(edge_x_test(c,xlo,yhi,zhi,xhi,ylo,zlo)) continue;} 00583 else {if(face_y_test(c,xlo,yhi,zlo,xhi,zhi)) continue;} 00584 } else { 00585 if(ek>k) {if(face_z_test(c,xlo,ylo,zlo,xhi,yhi)) continue;} 00586 else if(ek<k) {if(face_z_test(c,xlo,ylo,zhi,xhi,yhi)) continue;} 00587 else voro_fatal_error("Compute cell routine revisiting central block, which should never\nhappen.",VOROPP_INTERNAL_ERROR); 00588 } 00589 } 00590 00591 // Now compute the region that we are going to test over, and 00592 // set a displacement vector for the periodic cases 00593 ijk=con.region_index(ci,cj,ck,ei,ej,ek,qx,qy,qz,disp); 00594 00595 // Loop over all the elements in the block to test for cuts. It 00596 // would be possible to exclude some of these cases by testing 00597 // against mrs, but this will probably not save time. 00598 if(co[ijk]>0) { 00599 l=0;x2=x-qx;y2=y-qy;z2=z-qz; 00600 do { 00601 x1=p[ijk][ps*l]-x2; 00602 y1=p[ijk][ps*l+1]-y2; 00603 z1=p[ijk][ps*l+2]-z2; 00604 rs=con.r_scale(x1*x1+y1*y1+z1*z1,ijk,l); 00605 if(!c.nplane(x1,y1,z1,rs,id[ijk][l])) return false; 00606 l++; 00607 } while (l<co[ijk]); 00608 } 00609 00610 // If there's not much memory on the block list then add more 00611 if((qu_s<=qu_e?(qu_l-qu_e)+(qu_s-qu):qu_s-qu_e)<18) add_list_memory(qu_s,qu_e); 00612 00613 // Test the neighbors of the current block, and add them to the 00614 // block list if they haven't already been tested 00615 add_to_mask(ei,ej,ek,qu_e); 00616 } 00617 00618 return true; 00619 } 00620 00621 /** This function checks to see whether a particular block can possibly have 00622 * any intersection with a Voronoi cell, for the case when the closest point 00623 * from the cell center to the block is at a corner. 00624 * \param[in,out] c a reference to a Voronoi cell. 00625 * \param[in] (xl,yl,zl) the relative coordinates of the corner of the block 00626 * closest to the cell center. 00627 * \param[in] (xh,yh,zh) the relative coordinates of the corner of the block 00628 * furthest away from the cell center. 00629 * \return False if the block may intersect, true if does not. */ 00630 template<class c_class> 00631 template<class v_cell> 00632 bool voro_compute<c_class>::corner_test(v_cell &c,double xl,double yl,double zl,double xh,double yh,double zh) { 00633 if(c.plane_intersects_guess(xh,yl,zl,con.r_cutoff(xl*xh+yl*yl+zl*zl))) return false; 00634 if(c.plane_intersects(xh,yh,zl,con.r_cutoff(xl*xh+yl*yh+zl*zl))) return false; 00635 if(c.plane_intersects(xl,yh,zl,con.r_cutoff(xl*xl+yl*yh+zl*zl))) return false; 00636 if(c.plane_intersects(xl,yh,zh,con.r_cutoff(xl*xl+yl*yh+zl*zh))) return false; 00637 if(c.plane_intersects(xl,yl,zh,con.r_cutoff(xl*xl+yl*yl+zl*zh))) return false; 00638 if(c.plane_intersects(xh,yl,zh,con.r_cutoff(xl*xh+yl*yl+zl*zh))) return false; 00639 return true; 00640 } 00641 00642 /** This function checks to see whether a particular block can possibly have 00643 * any intersection with a Voronoi cell, for the case when the closest point 00644 * from the cell center to the block is on an edge which points along the x 00645 * direction. 00646 * \param[in,out] c a reference to a Voronoi cell. 00647 * \param[in] (x0,x1) the minimum and maximum relative x coordinates of the 00648 * block. 00649 * \param[in] (yl,zl) the relative y and z coordinates of the corner of the 00650 * block closest to the cell center. 00651 * \param[in] (yh,zh) the relative y and z coordinates of the corner of the 00652 * block furthest away from the cell center. 00653 * \return False if the block may intersect, true if does not. */ 00654 template<class c_class> 00655 template<class v_cell> 00656 inline bool voro_compute<c_class>::edge_x_test(v_cell &c,double x0,double yl,double zl,double x1,double yh,double zh) { 00657 if(c.plane_intersects_guess(x0,yl,zh,con.r_cutoff(yl*yl+zl*zh))) return false; 00658 if(c.plane_intersects(x1,yl,zh,con.r_cutoff(yl*yl+zl*zh))) return false; 00659 if(c.plane_intersects(x1,yl,zl,con.r_cutoff(yl*yl+zl*zl))) return false; 00660 if(c.plane_intersects(x0,yl,zl,con.r_cutoff(yl*yl+zl*zl))) return false; 00661 if(c.plane_intersects(x0,yh,zl,con.r_cutoff(yl*yh+zl*zl))) return false; 00662 if(c.plane_intersects(x1,yh,zl,con.r_cutoff(yl*yh+zl*zl))) return false; 00663 return true; 00664 } 00665 00666 /** This function checks to see whether a particular block can possibly have 00667 * any intersection with a Voronoi cell, for the case when the closest point 00668 * from the cell center to the block is on an edge which points along the y 00669 * direction. 00670 * \param[in,out] c a reference to a Voronoi cell. 00671 * \param[in] (y0,y1) the minimum and maximum relative y coordinates of the 00672 * block. 00673 * \param[in] (xl,zl) the relative x and z coordinates of the corner of the 00674 * block closest to the cell center. 00675 * \param[in] (xh,zh) the relative x and z coordinates of the corner of the 00676 * block furthest away from the cell center. 00677 * \return False if the block may intersect, true if does not. */ 00678 template<class c_class> 00679 template<class v_cell> 00680 inline bool voro_compute<c_class>::edge_y_test(v_cell &c,double xl,double y0,double zl,double xh,double y1,double zh) { 00681 if(c.plane_intersects_guess(xl,y0,zh,con.r_cutoff(xl*xl+zl*zh))) return false; 00682 if(c.plane_intersects(xl,y1,zh,con.r_cutoff(xl*xl+zl*zh))) return false; 00683 if(c.plane_intersects(xl,y1,zl,con.r_cutoff(xl*xl+zl*zl))) return false; 00684 if(c.plane_intersects(xl,y0,zl,con.r_cutoff(xl*xl+zl*zl))) return false; 00685 if(c.plane_intersects(xh,y0,zl,con.r_cutoff(xl*xh+zl*zl))) return false; 00686 if(c.plane_intersects(xh,y1,zl,con.r_cutoff(xl*xh+zl*zl))) return false; 00687 return true; 00688 } 00689 00690 /** This function checks to see whether a particular block can possibly have 00691 * any intersection with a Voronoi cell, for the case when the closest point 00692 * from the cell center to the block is on an edge which points along the z 00693 * direction. 00694 * \param[in,out] c a reference to a Voronoi cell. 00695 * \param[in] (z0,z1) the minimum and maximum relative z coordinates of the block. 00696 * \param[in] (xl,yl) the relative x and y coordinates of the corner of the 00697 * block closest to the cell center. 00698 * \param[in] (xh,yh) the relative x and y coordinates of the corner of the 00699 * block furthest away from the cell center. 00700 * \return False if the block may intersect, true if does not. */ 00701 template<class c_class> 00702 template<class v_cell> 00703 inline bool voro_compute<c_class>::edge_z_test(v_cell &c,double xl,double yl,double z0,double xh,double yh,double z1) { 00704 if(c.plane_intersects_guess(xl,yh,z0,con.r_cutoff(xl*xl+yl*yh))) return false; 00705 if(c.plane_intersects(xl,yh,z1,con.r_cutoff(xl*xl+yl*yh))) return false; 00706 if(c.plane_intersects(xl,yl,z1,con.r_cutoff(xl*xl+yl*yl))) return false; 00707 if(c.plane_intersects(xl,yl,z0,con.r_cutoff(xl*xl+yl*yl))) return false; 00708 if(c.plane_intersects(xh,yl,z0,con.r_cutoff(xl*xh+yl*yl))) return false; 00709 if(c.plane_intersects(xh,yl,z1,con.r_cutoff(xl*xh+yl*yl))) return false; 00710 return true; 00711 } 00712 00713 /** This function checks to see whether a particular block can possibly have 00714 * any intersection with a Voronoi cell, for the case when the closest point 00715 * from the cell center to the block is on a face aligned with the x direction. 00716 * \param[in,out] c a reference to a Voronoi cell. 00717 * \param[in] xl the minimum distance from the cell center to the face. 00718 * \param[in] (y0,y1) the minimum and maximum relative y coordinates of the 00719 * block. 00720 * \param[in] (z0,z1) the minimum and maximum relative z coordinates of the 00721 * block. 00722 * \return False if the block may intersect, true if does not. */ 00723 template<class c_class> 00724 template<class v_cell> 00725 inline bool voro_compute<c_class>::face_x_test(v_cell &c,double xl,double y0,double z0,double y1,double z1) { 00726 if(c.plane_intersects_guess(xl,y0,z0,con.r_cutoff(xl*xl))) return false; 00727 if(c.plane_intersects(xl,y0,z1,con.r_cutoff(xl*xl))) return false; 00728 if(c.plane_intersects(xl,y1,z1,con.r_cutoff(xl*xl))) return false; 00729 if(c.plane_intersects(xl,y1,z0,con.r_cutoff(xl*xl))) return false; 00730 return true; 00731 } 00732 00733 /** This function checks to see whether a particular block can possibly have 00734 * any intersection with a Voronoi cell, for the case when the closest point 00735 * from the cell center to the block is on a face aligned with the y direction. 00736 * \param[in,out] c a reference to a Voronoi cell. 00737 * \param[in] yl the minimum distance from the cell center to the face. 00738 * \param[in] (x0,x1) the minimum and maximum relative x coordinates of the 00739 * block. 00740 * \param[in] (z0,z1) the minimum and maximum relative z coordinates of the 00741 * block. 00742 * \return False if the block may intersect, true if does not. */ 00743 template<class c_class> 00744 template<class v_cell> 00745 inline bool voro_compute<c_class>::face_y_test(v_cell &c,double x0,double yl,double z0,double x1,double z1) { 00746 if(c.plane_intersects_guess(x0,yl,z0,con.r_cutoff(yl*yl))) return false; 00747 if(c.plane_intersects(x0,yl,z1,con.r_cutoff(yl*yl))) return false; 00748 if(c.plane_intersects(x1,yl,z1,con.r_cutoff(yl*yl))) return false; 00749 if(c.plane_intersects(x1,yl,z0,con.r_cutoff(yl*yl))) return false; 00750 return true; 00751 } 00752 00753 /** This function checks to see whether a particular block can possibly have 00754 * any intersection with a Voronoi cell, for the case when the closest point 00755 * from the cell center to the block is on a face aligned with the z direction. 00756 * \param[in,out] c a reference to a Voronoi cell. 00757 * \param[in] zl the minimum distance from the cell center to the face. 00758 * \param[in] (x0,x1) the minimum and maximum relative x coordinates of the 00759 * block. 00760 * \param[in] (y0,y1) the minimum and maximum relative y coordinates of the 00761 * block. 00762 * \return False if the block may intersect, true if does not. */ 00763 template<class c_class> 00764 template<class v_cell> 00765 inline bool voro_compute<c_class>::face_z_test(v_cell &c,double x0,double y0,double zl,double x1,double y1) { 00766 if(c.plane_intersects_guess(x0,y0,zl,con.r_cutoff(zl*zl))) return false; 00767 if(c.plane_intersects(x0,y1,zl,con.r_cutoff(zl*zl))) return false; 00768 if(c.plane_intersects(x1,y1,zl,con.r_cutoff(zl*zl))) return false; 00769 if(c.plane_intersects(x1,y0,zl,con.r_cutoff(zl*zl))) return false; 00770 return true; 00771 } 00772 00773 00774 /** This routine checks to see whether a point is within a particular distance 00775 * of a nearby region. If the point is within the distance of the region, then 00776 * the routine returns true, and computes the maximum distance from the point 00777 * to the region. Otherwise, the routine returns false. 00778 * \param[in] (di,dj,dk) the position of the nearby region to be tested, 00779 * relative to the region that the point is in. 00780 * \param[in] (fx,fy,fz) the displacement of the point within its region. 00781 * \param[in] (gxs,gys,gzs) the maximum squared distances from the point to the 00782 * sides of its region. 00783 * \param[out] crs a reference in which to return the maximum distance to the 00784 * region (only computed if the routine returns positive). 00785 * \param[in] mrs the distance to be tested. 00786 * \return False if the region is further away than mrs, true if the region in 00787 * within mrs.*/ 00788 template<class c_class> 00789 bool voro_compute<c_class>::compute_min_max_radius(int di,int dj,int dk,double fx,double fy,double fz,double gxs,double gys,double gzs,double &crs,double mrs) { 00790 double xlo,ylo,zlo; 00791 if(di>0) { 00792 xlo=di*boxx-fx; 00793 crs=xlo*xlo; 00794 if(dj>0) { 00795 ylo=dj*boxy-fy; 00796 crs+=ylo*ylo; 00797 if(dk>0) { 00798 zlo=dk*boxz-fz; 00799 crs+=zlo*zlo;if(con.r_cutoff(crs)>mrs) return true; 00800 crs+=bxsq+2*(boxx*xlo+boxy*ylo+boxz*zlo); 00801 } else if(dk<0) { 00802 zlo=(dk+1)*boxz-fz; 00803 crs+=zlo*zlo;if(con.r_cutoff(crs)>mrs) return true; 00804 crs+=bxsq+2*(boxx*xlo+boxy*ylo-boxz*zlo); 00805 } else { 00806 if(con.r_cutoff(crs)>mrs) return true; 00807 crs+=boxx*(2*xlo+boxx)+boxy*(2*ylo+boxy)+gzs; 00808 } 00809 } else if(dj<0) { 00810 ylo=(dj+1)*boxy-fy; 00811 crs+=ylo*ylo; 00812 if(dk>0) { 00813 zlo=dk*boxz-fz; 00814 crs+=zlo*zlo;if(con.r_cutoff(crs)>mrs) return true; 00815 crs+=bxsq+2*(boxx*xlo-boxy*ylo+boxz*zlo); 00816 } else if(dk<0) { 00817 zlo=(dk+1)*boxz-fz; 00818 crs+=zlo*zlo;if(con.r_cutoff(crs)>mrs) return true; 00819 crs+=bxsq+2*(boxx*xlo-boxy*ylo-boxz*zlo); 00820 } else { 00821 if(con.r_cutoff(crs)>mrs) return true; 00822 crs+=boxx*(2*xlo+boxx)+boxy*(-2*ylo+boxy)+gzs; 00823 } 00824 } else { 00825 if(dk>0) { 00826 zlo=dk*boxz-fz; 00827 crs+=zlo*zlo;if(con.r_cutoff(crs)>mrs) return true; 00828 crs+=boxz*(2*zlo+boxz); 00829 } else if(dk<0) { 00830 zlo=(dk+1)*boxz-fz; 00831 crs+=zlo*zlo;if(con.r_cutoff(crs)>mrs) return true; 00832 crs+=boxz*(-2*zlo+boxz); 00833 } else { 00834 if(con.r_cutoff(crs)>mrs) return true; 00835 crs+=gzs; 00836 } 00837 crs+=gys+boxx*(2*xlo+boxx); 00838 } 00839 } else if(di<0) { 00840 xlo=(di+1)*boxx-fx; 00841 crs=xlo*xlo; 00842 if(dj>0) { 00843 ylo=dj*boxy-fy; 00844 crs+=ylo*ylo; 00845 if(dk>0) { 00846 zlo=dk*boxz-fz; 00847 crs+=zlo*zlo;if(con.r_cutoff(crs)>mrs) return true; 00848 crs+=bxsq+2*(-boxx*xlo+boxy*ylo+boxz*zlo); 00849 } else if(dk<0) { 00850 zlo=(dk+1)*boxz-fz; 00851 crs+=zlo*zlo;if(con.r_cutoff(crs)>mrs) return true; 00852 crs+=bxsq+2*(-boxx*xlo+boxy*ylo-boxz*zlo); 00853 } else { 00854 if(con.r_cutoff(crs)>mrs) return true; 00855 crs+=boxx*(-2*xlo+boxx)+boxy*(2*ylo+boxy)+gzs; 00856 } 00857 } else if(dj<0) { 00858 ylo=(dj+1)*boxy-fy; 00859 crs+=ylo*ylo; 00860 if(dk>0) { 00861 zlo=dk*boxz-fz; 00862 crs+=zlo*zlo;if(con.r_cutoff(crs)>mrs) return true; 00863 crs+=bxsq+2*(-boxx*xlo-boxy*ylo+boxz*zlo); 00864 } else if(dk<0) { 00865 zlo=(dk+1)*boxz-fz; 00866 crs+=zlo*zlo;if(con.r_cutoff(crs)>mrs) return true; 00867 crs+=bxsq+2*(-boxx*xlo-boxy*ylo-boxz*zlo); 00868 } else { 00869 if(con.r_cutoff(crs)>mrs) return true; 00870 crs+=boxx*(-2*xlo+boxx)+boxy*(-2*ylo+boxy)+gzs; 00871 } 00872 } else { 00873 if(dk>0) { 00874 zlo=dk*boxz-fz; 00875 crs+=zlo*zlo;if(con.r_cutoff(crs)>mrs) return true; 00876 crs+=boxz*(2*zlo+boxz); 00877 } else if(dk<0) { 00878 zlo=(dk+1)*boxz-fz; 00879 crs+=zlo*zlo;if(con.r_cutoff(crs)>mrs) return true; 00880 crs+=boxz*(-2*zlo+boxz); 00881 } else { 00882 if(con.r_cutoff(crs)>mrs) return true; 00883 crs+=gzs; 00884 } 00885 crs+=gys+boxx*(-2*xlo+boxx); 00886 } 00887 } else { 00888 if(dj>0) { 00889 ylo=dj*boxy-fy; 00890 crs=ylo*ylo; 00891 if(dk>0) { 00892 zlo=dk*boxz-fz; 00893 crs+=zlo*zlo;if(con.r_cutoff(crs)>mrs) return true; 00894 crs+=boxz*(2*zlo+boxz); 00895 } else if(dk<0) { 00896 zlo=(dk+1)*boxz-fz; 00897 crs+=zlo*zlo;if(con.r_cutoff(crs)>mrs) return true; 00898 crs+=boxz*(-2*zlo+boxz); 00899 } else { 00900 if(con.r_cutoff(crs)>mrs) return true; 00901 crs+=gzs; 00902 } 00903 crs+=boxy*(2*ylo+boxy); 00904 } else if(dj<0) { 00905 ylo=(dj+1)*boxy-fy; 00906 crs=ylo*ylo; 00907 if(dk>0) { 00908 zlo=dk*boxz-fz; 00909 crs+=zlo*zlo;if(con.r_cutoff(crs)>mrs) return true; 00910 crs+=boxz*(2*zlo+boxz); 00911 } else if(dk<0) { 00912 zlo=(dk+1)*boxz-fz; 00913 crs+=zlo*zlo;if(con.r_cutoff(crs)>mrs) return true; 00914 crs+=boxz*(-2*zlo+boxz); 00915 } else { 00916 if(con.r_cutoff(crs)>mrs) return true; 00917 crs+=gzs; 00918 } 00919 crs+=boxy*(-2*ylo+boxy); 00920 } else { 00921 if(dk>0) { 00922 zlo=dk*boxz-fz;crs=zlo*zlo;if(con.r_cutoff(crs)>mrs) return true; 00923 crs+=boxz*(2*zlo+boxz); 00924 } else if(dk<0) { 00925 zlo=(dk+1)*boxz-fz;crs=zlo*zlo;if(con.r_cutoff(crs)>mrs) return true; 00926 crs+=boxz*(-2*zlo+boxz); 00927 } else { 00928 crs=0; 00929 voro_fatal_error("Min/max radius function called for central block, which should never\nhappen.",VOROPP_INTERNAL_ERROR); 00930 } 00931 crs+=gys; 00932 } 00933 crs+=gxs; 00934 } 00935 return false; 00936 } 00937 00938 template<class c_class> 00939 bool voro_compute<c_class>::compute_min_radius(int di,int dj,int dk,double fx,double fy,double fz,double mrs) { 00940 double t,crs; 00941 00942 if(di>0) {t=di*boxx-fx;crs=t*t;} 00943 else if(di<0) {t=(di+1)*boxx-fx;crs=t*t;} 00944 else crs=0; 00945 00946 if(dj>0) {t=dj*boxy-fy;crs+=t*t;} 00947 else if(dj<0) {t=(dj+1)*boxy-fy;crs+=t*t;} 00948 00949 if(dk>0) {t=dk*boxz-fz;crs+=t*t;} 00950 else if(dk<0) {t=(dk+1)*boxz-fz;crs+=t*t;} 00951 00952 return crs>con.r_max_add(mrs); 00953 } 00954 00955 /** Adds memory to the queue. 00956 * \param[in,out] qu_s a reference to the queue start pointer. 00957 * \param[in,out] qu_e a reference to the queue end pointer. */ 00958 template<class c_class> 00959 inline void voro_compute<c_class>::add_list_memory(int*& qu_s,int*& qu_e) { 00960 qu_size<<=1; 00961 int *qu_n=new int[qu_size],*qu_c=qu_n; 00962 #if VOROPP_VERBOSE >=2 00963 fprintf(stderr,"List memory scaled up to %d\n",qu_size); 00964 #endif 00965 if(qu_s<=qu_e) { 00966 while(qu_s<qu_e) *(qu_c++)=*(qu_s++); 00967 } else { 00968 while(qu_s<qu_l) *(qu_c++)=*(qu_s++);qu_s=qu; 00969 while(qu_s<qu_e) *(qu_c++)=*(qu_s++); 00970 } 00971 delete [] qu; 00972 qu_s=qu=qu_n; 00973 qu_l=qu+qu_size; 00974 qu_e=qu_c; 00975 } 00976 00977 // Explicit template instantiation 00978 template voro_compute<container>::voro_compute(container&,int,int,int); 00979 template voro_compute<container_poly>::voro_compute(container_poly&,int,int,int); 00980 template bool voro_compute<container>::compute_cell(voronoicell&,int,int,int,int,int); 00981 template bool voro_compute<container>::compute_cell(voronoicell_neighbor&,int,int,int,int,int); 00982 template void voro_compute<container>::find_voronoi_cell(double,double,double,int,int,int,int,particle_record&,double&); 00983 template bool voro_compute<container_poly>::compute_cell(voronoicell&,int,int,int,int,int); 00984 template bool voro_compute<container_poly>::compute_cell(voronoicell_neighbor&,int,int,int,int,int); 00985 template void voro_compute<container_poly>::find_voronoi_cell(double,double,double,int,int,int,int,particle_record&,double&); 00986 00987 // Explicit template instantiation 00988 template voro_compute<container_periodic>::voro_compute(container_periodic&,int,int,int); 00989 template voro_compute<container_periodic_poly>::voro_compute(container_periodic_poly&,int,int,int); 00990 template bool voro_compute<container_periodic>::compute_cell(voronoicell&,int,int,int,int,int); 00991 template bool voro_compute<container_periodic>::compute_cell(voronoicell_neighbor&,int,int,int,int,int); 00992 template void voro_compute<container_periodic>::find_voronoi_cell(double,double,double,int,int,int,int,particle_record&,double&); 00993 template bool voro_compute<container_periodic_poly>::compute_cell(voronoicell&,int,int,int,int,int); 00994 template bool voro_compute<container_periodic_poly>::compute_cell(voronoicell_neighbor&,int,int,int,int,int); 00995 template void voro_compute<container_periodic_poly>::find_voronoi_cell(double,double,double,int,int,int,int,particle_record&,double&); 00996 00997 }