Reset platonic code.
[voro++.git] / branches / dynamic / src / container.cc
blob854e82621736ce234f33dd6e1abc5cfa9bf808dc
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 : July 1st 2008
7 /** \file container.cc
8 * \brief Function implementations for the container_base template and related
9 * classes. */
11 #include "cell.hh"
12 #include "container.hh"
14 /** Container constructor. The first six arguments set the corners of the box to
15 * be (xa,ya,za) and (xb,yb,zb). The box is then divided into an nx by ny by nz
16 * grid of blocks, set by the following three arguments. The next three
17 * arguments are booleans, which set the periodicity in each direction. The
18 * final argument sets the amount of memory allocated to each block. */
19 template<class r_option>
20 container_base<r_option>::container_base(fpoint xa,fpoint xb,fpoint ya,fpoint yb,fpoint za,fpoint zb,
21 int xn,int yn,int zn,const bool xper,const bool yper,const bool zper,int memi)
22 : ax(xa),bx(xb),ay(ya),by(yb),az(za),bz(zb),
23 xsp(xn/(xb-xa)),ysp(yn/(yb-ya)),zsp(zn/(zb-za)),
24 nx(xn),ny(yn),nz(zn),nxy(xn*yn),nxyz(xn*yn*zn),
25 hx(xper?2*xn+1:xn),hy(yper?2*yn+1:yn),hz(zper?2*zn+1:zn),hxy(hx*hy),hxyz(hx*hy*hz),
26 xperiodic(xper),yperiodic(yper),zperiodic(zper),
27 mv(0),wall_number(0),current_wall_size(init_wall_size),
28 radius(this),sz(radius.mem_size) {
29 int l;
30 co=new int[nxyz];
31 for(l=0;l<nxyz;l++) co[l]=0;
32 mem=new int[nxyz];
33 for(l=0;l<nxyz;l++) mem[l]=memi;
34 id=new int*[nxyz];
35 for(l=0;l<nxyz;l++) id[l]=new int[memi];
36 p=new fpoint*[nxyz];
37 for(l=0;l<nxyz;l++) p[l]=new fpoint[sz*memi];
38 mask=new unsigned int[hxyz];
39 for(l=0;l<hxyz;l++) mask[l]=0;
40 s_size=3*(hxy+hz*(hx+hy));if(s_size<18) s_size=18;
41 sl=new int[s_size];
42 walls=new wall*[current_wall_size];
43 mrad=new fpoint[hgridsq*seq_length];
44 initialize_radii();
47 /** This function is called during container construction. The routine scans
48 * all of the worklists in the wl[] array. For a given worklist of blocks
49 * labeled \f$w_1\f$ to \f$w_n\f$, it computes a sequence \f$r_0\f$ to
50 * \f$r_n\f$ so that $r_i$ is the minimum distance to all the blocks
51 * \f$w_{j}\f$ where \f$j>i\f$ and all blocks outside the worklist. The values
52 * of \f$r_n\f$ is calculated first, as the minimum distance to any block in
53 * the shell surrounding the worklist. The \f$r_i\f$ are then computed in
54 * reverse order by considering the distance to \f$w_{i+1}\f$.
56 template<class r_option>
57 void container_base<r_option>::initialize_radii() {
58 const unsigned int b1=1<<21,b2=1<<22,b3=1<<24,b4=1<<25,b5=1<<27,b6=1<<28;
59 const fpoint xstep=(bx-ax)/nx/fgrid;
60 const fpoint ystep=(by-ay)/ny/fgrid;
61 const fpoint zstep=(bz-az)/nz/fgrid;
62 int i,j,k,lx,ly,lz,l=0,q;
63 unsigned int *e=const_cast<unsigned int*> (wl);
64 fpoint xlo,ylo,zlo,xhi,yhi,zhi,minr;fpoint *radp=mrad;
65 unsigned int f;
66 for(zlo=0,zhi=zstep,lz=0;lz<hgrid;zlo=zhi,zhi+=zstep,lz++) {
67 for(ylo=0,yhi=ystep,ly=0;ly<hgrid;ylo=yhi,yhi+=ystep,ly++) {
68 for(xlo=0,xhi=xstep,lx=0;lx<hgrid;xlo=xhi,xhi+=xstep,l++,lx++) {
69 minr=large_number;
70 for(q=e[0]+1;q<seq_length;q++) {
71 f=e[q];
72 i=(f&127)-64;
73 j=(f>>7&127)-64;
74 k=(f>>14&127)-64;
75 if((f&b2)==b2) {
76 compute_minimum(minr,xlo,xhi,ylo,yhi,zlo,zhi,i-1,j,k);
77 if((f&b1)==0) compute_minimum(minr,xlo,xhi,ylo,yhi,zlo,zhi,i+1,j,k);
78 } else if((f&b1)==b1) compute_minimum(minr,xlo,xhi,ylo,yhi,zlo,zhi,i+1,j,k);
79 if((f&b4)==b4) {
80 compute_minimum(minr,xlo,xhi,ylo,yhi,zlo,zhi,i,j-1,k);
81 if((f&b3)==0) compute_minimum(minr,xlo,xhi,ylo,yhi,zlo,zhi,i,j+1,k);
82 } else if((f&b3)==b3) compute_minimum(minr,xlo,xhi,ylo,yhi,zlo,zhi,i,j+1,k);
83 if((f&b6)==b6) {
84 compute_minimum(minr,xlo,xhi,ylo,yhi,zlo,zhi,i,j,k-1);
85 if((f&b5)==0) compute_minimum(minr,xlo,xhi,ylo,yhi,zlo,zhi,i,j,k+1);
86 } else if((f&b5)==b5) compute_minimum(minr,xlo,xhi,ylo,yhi,zlo,zhi,i,j,k+1);
88 q--;
89 while(q>0) {
90 radp[q]=minr;
91 f=e[q];
92 i=(f&127)-64;
93 j=(f>>7&127)-64;
94 k=(f>>14&127)-64;
95 compute_minimum(minr,xlo,xhi,ylo,yhi,zlo,zhi,i,j,k);
96 q--;
98 radp[0]=minr;
99 e+=seq_length;
100 radp+=seq_length;
106 /** Computes the minimum distance from a subregion to a given block. If this distance
107 * is smaller than the value of minr, then it passes
108 * \param[in] &minr a pointer to the current minimum distance. If distance
109 * computed in this function is smaller, then this distance is set to the new
110 * one.
111 * \param[in] (&xlo,&ylo,&zlo) the lower coordinates of the subregion being
112 * considered.
113 * \param[in] (&xhi,&yhi,&zhi) the upper coordinates of the subregion being
114 * considered.
115 * \param[in] (ti,tj,tk) the coordinates of the block. */
116 template<class r_option>
117 inline void container_base<r_option>::compute_minimum(fpoint &minr,fpoint &xlo,fpoint &xhi,fpoint &ylo,fpoint &yhi,fpoint &zlo,fpoint &zhi,int ti,int tj,int tk) {
118 const fpoint boxx=(bx-ax)/nx,boxy=(by-ay)/ny,boxz=(bz-az)/nz;
119 fpoint radsq,temp;
120 if(ti>0) {temp=boxx*ti-xhi;radsq=temp*temp;}
121 else if(ti<0) {temp=xlo-boxx*(1+ti);radsq=temp*temp;}
122 else radsq=0;
124 if(tj>0) {temp=boxy*tj-yhi;radsq+=temp*temp;}
125 else if(tj<0) {temp=ylo-boxy*(1+tj);radsq+=temp*temp;}
127 if(tk>0) {temp=boxz*tk-zhi;radsq+=temp*temp;}
128 else if(tk<0) {temp=zlo-boxz*(1+tk);radsq+=temp*temp;}
130 if(radsq<minr) minr=radsq;
133 /** Container destructor - free memory. */
134 template<class r_option>
135 container_base<r_option>::~container_base() {
136 int l;
137 for(l=0;l<nxyz;l++) delete [] p[l];
138 for(l=0;l<nxyz;l++) delete [] id[l];
139 delete [] p;
140 delete [] id;
141 delete [] mem;
142 delete [] co;
143 delete [] mask;
144 delete [] sl;
145 delete [] walls;
146 delete [] mrad;
149 /** Dumps all the particle positions and identifiers to an output stream.
150 * \param[in] &os the output stream to write to. */
151 template<class r_option>
152 void container_base<r_option>::draw_particles(ostream &os) {
153 int c,l,i;
154 for(l=0;l<nxyz;l++) {
155 for(c=0;c<co[l];c++) {
156 os << id[l][c];
157 for(i=sz*c;i<sz*(c+1);i++) os << " " << p[l][i];
158 os << "\n";
163 /** Dumps all the particle positions and identifiers in the LAMMPS restart
164 * format to an output stream.
165 * \param[in] &os the output stream to write to.
166 * \param[in] timestep the value of the "ITEM: TIMESTEP" field to write in the
167 * restart file.
168 * \param[in] scaled a boolean value of whether to scale the particle
169 * coordinates to the range (0,1), as used in some LAMMPS implementations. */
170 template<class r_option>
171 void container_base<r_option>::draw_lammps_restart(ostream &os,fpoint timestep,bool scaled) {
172 const fpoint facx=1/(bx-ax),facy=1/(by-ay),facz=1/(bz-az);
173 int l=0,ijk=0;
174 while(ijk<nxyz) l+=co[ijk++];
175 os << " ITEM: TIMESTEP\n" << timestep;
176 os << "\n ITEM: NUMBER OF ATOMS\n" << l;
177 os << "\n ITEM: BOX BOUNDS\n";
178 os << ax << " " << bx << "\n";
179 os << ay << " " << by << "\n";
180 os << az << " " << bz << "\n ITEM: ATOMS\n";
181 for(ijk=0;ijk<nxyz;ijk++) for(l=0;l<co[ijk];l++) {
182 os << id[ijk][l] << " 1 ";
183 radius.diam(os,ijk,l);
184 os << " ";
185 if (scaled) {
186 os << (p[ijk][sz*l]-ax)*facx << " " << (p[ijk][sz*l+1]-ay)*facy << " " << (p[ijk][sz*l+2]-az)*facz;
187 } else {
188 os << p[ijk][sz*l] << " " << p[ijk][sz*l+1] << " " << p[ijk][sz*l+2];
190 os << "\n";
194 template<class r_option>
195 void container_base<r_option>::skip_lammps_restart(istream &is) {
196 int i,n;
197 static char q[256];
198 for(i=0;i<3;i++) is.getline(q,256);
199 is >> n;
200 if (n>100000000) throw fatal_error("Particle number exceeds safe limit");
201 for(i=0;i<6+n;i++) is.getline(q,256);
204 template<class r_option>
205 void container_base<r_option>::import_lammps_restart(istream &is,bool scaled) {
206 int i,n;
207 static char q[256];
208 clear();
209 for(i=0;i<3;i++) is.getline(q,256);
210 is >> n;
211 if (n>100000000) throw fatal_error("Particle number exceeds safe limit");
212 for(i=0;i<6;i++) is.getline(q,256);
213 radius.import_lammps(is,n,scaled);
214 is.getline(q,256);
217 /** An overloaded version of the draw_particles() routine, that just prints
218 * to standard output. */
219 template<class r_option>
220 void container_base<r_option>::draw_particles() {
221 draw_particles(cout);
224 /** An overloaded version of the draw_particles() routine, that outputs
225 * the particle positions to a file.
226 * \param[in] filename the file to write to. */
227 template<class r_option>
228 void container_base<r_option>::draw_particles(const char *filename) {
229 ofstream os;
230 os.open(filename,ofstream::out|ofstream::trunc);
231 draw_particles(os);
232 os.close();
235 /** Dumps all the particle positions in the POV-Ray format. */
236 template<class r_option>
237 void container_base<r_option>::draw_particles_pov(ostream &os) {
238 int l,c;
239 for(l=0;l<nxyz;l++) {
240 for(c=0;c<co[l];c++) {
241 os << "// id " << id[l][c] << "\n";
242 os << "sphere{<" << p[l][sz*c] << "," << p[l][sz*c+1] << ","
243 << p[l][sz*c+2] << ">,";
244 radius.rad(os,l,c);
245 os << "}\n";
250 /** An overloaded version of the draw_particles_pov() routine, that just prints
251 * to standard output. */
252 template<class r_option>
253 void container_base<r_option>::draw_particles_pov() {
254 draw_particles_pov(cout);
257 /** An overloaded version of the draw_particles_pov() routine, that outputs
258 * the particle positions to a file.
259 * \param[in] filename the file to write to. */
260 template<class r_option>
261 void container_base<r_option>::draw_particles_pov(const char *filename) {
262 ofstream os;
263 os.open(filename,ofstream::out|ofstream::trunc);
264 draw_particles_pov(os);
265 os.close();
268 /** Put a particle into the correct region of the container. */
269 template<class r_option>
270 void container_base<r_option>::put(int n,fpoint x,fpoint y,fpoint z) {
271 if(x>ax&&y>ay&&z>az) {
272 int i,j,k;
273 i=int((x-ax)*xsp);j=int((y-ay)*ysp);k=int((z-az)*zsp);
274 if(i<nx&&j<ny&&k<nz) {
275 i+=nx*j+nxy*k;
276 if(co[i]==mem[i]) add_particle_memory(i);
277 p[i][sz*co[i]]=x;p[i][sz*co[i]+1]=y;p[i][sz*co[i]+2]=z;
278 radius.store_radius(i,co[i],0.5);
279 id[i][co[i]++]=n;
284 /** Put a particle into the correct region of the container.
285 * \param[in] n The numerical ID of the inserted particle.
286 * \param[in] (x,y,z) The position vector of the inserted particle.
287 * \param[in] r The radius of the particle.*/
288 template<class r_option>
289 void container_base<r_option>::put(int n,fpoint x,fpoint y,fpoint z,fpoint r) {
290 if(x>ax&&y>ay&&z>az) {
291 int i,j,k;
292 i=int((x-ax)*xsp);j=int((y-ay)*ysp);k=int((z-az)*zsp);
293 if(i<nx&&j<ny&&k<nz) {
294 i+=nx*j+nxy*k;
295 if(co[i]==mem[i]) add_particle_memory(i);
296 p[i][sz*co[i]]=x;p[i][sz*co[i]+1]=y;p[i][sz*co[i]+2]=z;
297 radius.store_radius(i,co[i],r);
298 id[i][co[i]++]=n;
303 /** Increase memory for a particular region. */
304 template<class r_option>
305 void container_base<r_option>::add_particle_memory(int i) {
306 int *idp;fpoint *pp;
307 int l,nmem=2*mem[i];
308 #if VOROPP_VERBOSE >=3
309 cerr << "Particle memory in region " << i << " scaled up to " << nmem << endl;
310 #endif
311 if(nmem>max_particle_memory) throw fatal_error("Absolute maximum memory allocation exceeded");
312 idp=new int[nmem];
313 for(l=0;l<co[i];l++) idp[l]=id[i][l];
314 pp=new fpoint[sz*nmem];
315 for(l=0;l<sz*co[i];l++) pp[l]=p[i][l];
316 mem[i]=nmem;
317 delete [] id[i];id[i]=idp;
318 delete [] p[i];p[i]=pp;
321 /** Add list memory. */
322 template<class r_option>
323 inline void container_base<r_option>::add_list_memory() {
324 int i,j=0,*ps;
325 ps=new int[s_size*2];
326 #if VOROPP_VERBOSE >=2
327 cerr << "List memory scaled up to " << s_size*2 << endl;
328 #endif
329 if(s_start<=s_end) {
330 for(i=s_start;i<s_end;i++) ps[j++]=sl[i];
331 } else {
332 for(i=s_start;i<s_size;i++) ps[j++]=sl[i];
333 for(i=0;i<s_end;i++) ps[j++]=sl[i];
335 s_size*=2;
336 s_start=0;s_end=j;
337 delete [] sl;sl=ps;
340 /** Import a list of particles from standard input. */
341 template<class r_option>
342 void container_base<r_option>::import(istream &is) {
343 radius.import(is);
346 /** An overloaded version of the import routine, that reads the standard input.
348 template<class r_option>
349 inline void container_base<r_option>::import() {
350 import(cin);
353 /** An overloaded version of the import routine, that reads in particles from
354 * a particular file.
355 * \param[in] filename The name of the file to read from. */
356 template<class r_option>
357 inline void container_base<r_option>::import(const char *filename) {
358 ifstream is;
359 is.open(filename,ifstream::in);
360 import(is);
361 is.close();
364 /** Outputs the number of particles within each region. */
365 template<class r_option>
366 void container_base<r_option>::region_count() {
367 int i,j,k,ijk=0;
368 for(k=0;k<nz;k++) {
369 for(j=0;j<ny;j++) {
370 for(i=0;i<nx;i++) cout << "Region (" << i << "," << j << "," << k << "): " << co[ijk++] << " particles" << endl;
375 /** Clears a container of particles. */
376 template<class r_option>
377 void container_base<r_option>::clear() {
378 for(int ijk=0;ijk<nxyz;ijk++) co[ijk]=0;
379 radius.clear_max();
382 /** Computes the Voronoi cells for all particles within a box with corners
383 * (xmin,ymin,zmin) and (xmax,ymax,zmax), and saves the output in a format
384 * that can be read by gnuplot. */
385 template<class r_option>
386 void container_base<r_option>::draw_cells_gnuplot(const char *filename,fpoint xmin,fpoint xmax,fpoint ymin,fpoint ymax,fpoint zmin,fpoint zmax) {
387 fpoint x,y,z,px,py,pz;
388 voropp_loop l1(this);
389 int q,s;
390 voronoicell c;
391 ofstream os;
392 os.open(filename,ofstream::out|ofstream::trunc);
393 s=l1.init(xmin,xmax,ymin,ymax,zmin,zmax,px,py,pz);
394 do {
395 for(q=0;q<co[s];q++) {
396 x=p[s][sz*q]+px;y=p[s][sz*q+1]+py;z=p[s][sz*q+2]+pz;
397 if(x>xmin&&x<xmax&&y>ymin&&y<ymax&&z>zmin&&z<zmax) {
398 if (compute_cell(c,l1.ip,l1.jp,l1.kp,s,q,x,y,z)) c.draw_gnuplot(os,x,y,z);
401 } while((s=l1.inc(px,py,pz))!=-1);
402 os.close();
405 /** If only a filename is supplied to draw_cells_gnuplot(), then assume that we are
406 * calculating the entire simulation region. */
407 template<class r_option>
408 void container_base<r_option>::draw_cells_gnuplot(const char *filename) {
409 draw_cells_gnuplot(filename,ax,bx,ay,by,az,bz);
412 /** Computes the Voronoi cells for all particles within a box with corners
413 * (xmin,ymin,zmin) and (xmax,ymax,zmax), and saves the output in a format
414 * that can be read by gnuplot.*/
415 template<class r_option>
416 void container_base<r_option>::draw_cells_pov(const char *filename,fpoint xmin,fpoint xmax,fpoint ymin,fpoint ymax,fpoint zmin,fpoint zmax) {
417 fpoint x,y,z,px,py,pz;
418 voropp_loop l1(this);
419 int q,s;
420 voronoicell_neighbor c;
421 ofstream os;
422 os.open(filename,ofstream::out|ofstream::trunc);
423 s=l1.init(xmin,xmax,ymin,ymax,zmin,zmax,px,py,pz);
424 do {
425 for(q=0;q<co[s];q++) {
426 os << "// cell " << id[s][q] << "\n";
427 x=p[s][sz*q]+px;y=p[s][sz*q+1]+py;z=p[s][sz*q+2]+pz;
428 if(x>xmin&&x<xmax&&y>ymin&&y<ymax&&z>zmin&&z<zmax) {
429 if (compute_cell(c,l1.ip,l1.jp,l1.kp,s,q,x,y,z)) c.draw_pov(os,x,y,z);
432 } while((s=l1.inc(px,py,pz))!=-1);
433 os.close();
436 /** If only a filename is supplied to draw_cells_pov(), then assume that we are
437 * calculating the entire simulation region.*/
438 template<class r_option>
439 void container_base<r_option>::draw_cells_pov(const char *filename) {
440 draw_cells_pov(filename,ax,bx,ay,by,az,bz);
443 /** This function computes all the cells in the container, but does nothing
444 * with the output. It is useful for measuring the pure computation time
445 * of the Voronoi algorithm, without any extraneous calculations, such as
446 * volume evaluation or cell output. */
447 template<class r_option>
448 void container_base<r_option>::compute_all_cells() {
449 voronoicell c;
450 int i,j,k,ijk=0,q;
451 for(k=0;k<nz;k++) for(j=0;j<ny;j++) for(i=0;i<nx;i++,ijk++) {
452 for(q=0;q<co[ijk];q++) compute_cell(c,i,j,k,ijk,q);
457 /** Computes the Voronoi volumes for all the particles, and stores the
458 * results according to the particle label in the fpoint array bb.*/
459 template<class r_option>
460 void container_base<r_option>::store_cell_volumes(fpoint *bb) {
461 voronoicell c;
462 int i,j,k,ijk=0,q;
463 for(k=0;k<nz;k++) for(j=0;j<ny;j++) for(i=0;i<nx;i++,ijk++) {
464 for(q=0;q<co[ijk];q++) {
465 if (compute_cell(c,i,j,k,ijk,q)) {
466 bb[id[ijk][q]]=c.volume();
467 } else {
468 bb[id[ijk][q]]=0;
474 /** Computes the local packing fraction at a point, by summing the volumes
475 * of all particles within a test sphere, and dividing by the sum of their
476 * Voronoi volumes that were previous computed using the store_cell_volumes()
477 * function.
478 * \param[in] *bb an array holding the Voronoi volumes of the particles.
479 * \param[in] (cx,cy,cz) the center of the test sphere.
480 * \param[in] r the radius of the test sphere. */
481 template<class r_option>
482 fpoint container_base<r_option>::packing_fraction(fpoint *bb,fpoint cx,fpoint cy,fpoint cz,fpoint r) {
483 voropp_loop l1(this);
484 fpoint px,py,pz,x,y,z,rsq=r*r,pvol=0,vvol=0;
485 int q,s;
486 s=l1.init(cx,cy,cz,r,px,py,pz);
487 do {
488 for(q=0;q<co[s];q++) {
489 x=p[s][sz*q]+px-cx;
490 y=p[s][sz*q+1]+py-cy;
491 z=p[s][sz*q+2]+pz-cz;
492 if (x*x+y*y+z*z<rsq) {
493 pvol+=radius.volume(s,q);
494 vvol+=bb[id[s][q]];
497 } while((s=l1.inc(px,py,pz))!=-1);
498 return vvol>tolerance?pvol/vvol*4.1887902047863909846168578443726:0;
501 /** Computes the local packing fraction at a point, by summing the volumes
502 * of all particles within test box, and dividing by the sum of their
503 * Voronoi volumes that were previous computed using the store_cell_volumes()
504 * function.
505 * \param[in] *bb an array holding the Voronoi volumes of the particles.
506 * \param[in] (xmin,ymin,zmin) the minimum coordinates of the box.
507 * \param[in] (xmax,ymax,zmax) the maximum coordinates of the box. */
508 template<class r_option>
509 fpoint container_base<r_option>::packing_fraction(fpoint *bb,fpoint xmin,fpoint xmax,fpoint ymin,fpoint ymax,fpoint zmin,fpoint zmax) {
510 voropp_loop l1(this);
511 fpoint x,y,z,px,py,pz,pvol=0,vvol=0;
512 int q,s;
513 s=l1.init(xmin,xmax,ymin,ymax,zmin,zmax,px,py,pz);
514 do {
515 for(q=0;q<co[s];q++) {
516 x=p[s][sz*q]+px;
517 y=p[s][sz*q+1]+py;
518 z=p[s][sz*q+2]+pz;
519 if(x>xmin&&x<xmax&&y>ymin&&y<ymax&&z>zmin&&z<zmax) {
520 pvol+=radius.volume(s,q);
521 vvol+=bb[id[s][q]];
524 } while((s=l1.inc(px,py,pz))!=-1);
525 return vvol>tolerance?pvol/vvol*4.1887902047863909846168578443726:0;
528 /** Computes the Voronoi volumes for all the particles, and stores the
529 * results according to the particle label in the fpoint array bb.*/
530 template<class r_option>
531 fpoint container_base<r_option>::sum_cell_volumes() {
532 voronoicell c;
533 int i,j,k,ijk=0,q;fpoint vol=0;
534 for(k=0;k<nz;k++) for(j=0;j<ny;j++) for(i=0;i<nx;i++,ijk++) {
535 for(q=0;q<co[ijk];q++) if (compute_cell(c,i,j,k,ijk,q)) vol+=c.volume();
537 return vol;
540 /** Prints a list of all particle labels, positions, and the number of faces to
541 * the standard output. */
542 template<class r_option>
543 inline void container_base<r_option>::count_all_faces(ostream &os) {
544 voronoicell c;
545 fpoint x,y,z;
546 int i,j,k,ijk=0,q;
547 for(k=0;k<nz;k++) for(j=0;j<ny;j++) for(i=0;i<nx;i++,ijk++) {
548 for(q=0;q<co[ijk];q++) {
549 x=p[ijk][sz*q];y=p[ijk][sz*q+1];z=p[ijk][sz*q+2];
550 os << id[ijk][q] << " " << x << " " << y << " " << z;
551 radius.print(os,ijk,q);
552 if (compute_cell(c,i,j,k,ijk,q,x,y,z)) {
553 os << " " << c.number_of_faces() << "\n";
554 } else os << " 0\n";
559 /** Prints a list of all particle labels, positions, and the number of faces to
560 * the standard output. */
561 template<class r_option>
562 void container_base<r_option>::count_all_faces() {
563 count_all_faces(cout);
566 /** An overloaded version of count_all_faces(), which outputs the result to a
567 * particular file.
568 * \param[in] filename The name of the file to write to. */
569 template<class r_option>
570 void container_base<r_option>::count_all_faces(const char* filename) {
571 ofstream os;
572 os.open(filename,ofstream::out|ofstream::trunc);
573 count_all_faces(os);
574 os.close();
577 /** Prints a list of all particle labels, positions, and Voronoi volumes to the
578 * standard output. */
579 template<class r_option>
580 template<class n_option>
581 inline void container_base<r_option>::print_all(ostream &os,voronoicell_base<n_option> &c) {
582 fpoint x,y,z;
583 int i,j,k,ijk=0,q;
584 for(k=0;k<nz;k++) for(j=0;j<ny;j++) for(i=0;i<nx;i++,ijk++) {
585 for(q=0;q<co[ijk];q++) {
586 x=p[ijk][sz*q];y=p[ijk][sz*q+1];z=p[ijk][sz*q+2];
587 os << id[ijk][q] << " " << x << " " << y << " " << z;
588 radius.print(os,ijk,q);
589 if (compute_cell(c,i,j,k,ijk,q,x,y,z)) {
590 os << " " << c.volume();
591 c.neighbors(os);
592 os << "\n";
593 } else os << " 0\n";
598 /** Prints a list of all particle labels, positions, and Voronoi volumes to the
599 * standard output. */
600 template<class r_option>
601 void container_base<r_option>::print_all(ostream &os) {
602 voronoicell c;
603 print_all(os,c);
606 /** An overloaded version of print_all(), which just prints to standard output. */
607 template<class r_option>
608 void container_base<r_option>::print_all() {
609 voronoicell c;
610 print_all(cout,c);
613 /** An overloaded version of print_all(), which outputs the result to a particular
614 * file.
615 * \param[in] filename The name of the file to write to. */
616 template<class r_option>
617 inline void container_base<r_option>::print_all(const char* filename) {
618 voronoicell c;
619 ofstream os;
620 os.open(filename,ofstream::out|ofstream::trunc);
621 print_all(os,c);
622 os.close();
625 /** Prints a list of all particle labels, positions, Voronoi volumes, and a list
626 * of neighboring particles to an output stream.
627 * \param[in] os The output stream to print to.*/
628 template<class r_option>
629 void container_base<r_option>::print_all_neighbor(ostream &os) {
630 voronoicell_neighbor c;
631 print_all(os,c);
634 /** An overloaded version of print_all_neighbor(), which just prints to
635 * standard output. */
636 template<class r_option>
637 void container_base<r_option>::print_all_neighbor() {
638 voronoicell_neighbor c;
639 print_all(cout,c);
642 /** An overloaded version of print_all_neighbor(), which outputs the result to a
643 * particular file
644 * \param[in] filename The name of the file to write to. */
645 template<class r_option>
646 inline void container_base<r_option>::print_all_neighbor(const char* filename) {
647 voronoicell_neighbor c;
648 ofstream os;
649 os.open(filename,ofstream::out|ofstream::trunc);
650 print_all(os,c);
651 os.close();
654 /** Initialize the Voronoi cell to be the entire container. For non-periodic
655 * coordinates, this is set by the position of the walls. For periodic
656 * coordinates, the space is equally divided in either direction from the
657 * particle's initial position. That makes sense since those boundaries would
658 * be made by the neighboring periodic images of this particle. */
659 template<class r_option>
660 template<class n_option>
661 inline bool container_base<r_option>::initialize_voronoicell(voronoicell_base<n_option> &c,fpoint x,fpoint y,fpoint z) {
662 fpoint x1,x2,y1,y2,z1,z2;
663 if(xperiodic) x1=-(x2=0.5*(bx-ax));else {x1=ax-x;x2=bx-x;}
664 if(yperiodic) y1=-(y2=0.5*(by-ay));else {y1=ay-y;y2=by-y;}
665 if(zperiodic) z1=-(z2=0.5*(bz-az));else {z1=az-z;z2=bz-z;}
666 c.init(x1,x2,y1,y2,z1,z2);
667 for(int j=0;j<wall_number;j++) {
668 if (!(walls[j]->cut_cell(c,x,y,z))) return false;
670 return true;
673 /** This function tests to see if a given vector lies within the container
674 * bounds and any walls.
675 * \param[in] (x,y,z) The position vector to be tested.
676 * \return True if the point is inside the container, false if the point is
677 * outside. */
678 template<class r_option>
679 bool container_base<r_option>::point_inside(fpoint x,fpoint y,fpoint z) {
680 if(x<ax||x>bx||y<ay||y>by||z<az||z>bz) return false;
681 return point_inside_walls(x,y,z);
684 /** This function tests to see if a give vector lies within the walls that have
685 * been added to the container, but does not specifically check whether the
686 * vector lies within the container bounds.
687 * \param[in] (x,y,z) The position vector to be tested.
688 * \return True if the point is inside the container, false if the point is
689 * outside. */
690 template<class r_option>
691 bool container_base<r_option>::point_inside_walls(fpoint x,fpoint y,fpoint z) {
692 for(int j=0;j<wall_number;j++) if(!walls[j]->point_inside(x,y,z)) return false;
693 return true;
696 /** This routine is a simpler alternative to compute_cell(), that constructs
697 * the cell by testing over successively larger spherical shells of particles.
698 * For a container that is homogeneously filled with particles, this routine
699 * runs as fast as compute_cell(). However, it rapidly becomes inefficient
700 * for cases when the particles are not homogeneously distributed, or where
701 * parts of the container might not be filled. In that case, the spheres may
702 * grow very large before being cut off, leading to poor efficiency.
703 * \param[in] &c a reference to a voronoicell object.
704 * \param[in] (i,j,k) the coordinates of the block that the test particle is
705 * in.
706 * \param[in] ijk the index of the block that the test particle is in, set to
707 * i+nx*(j+ny*k).
708 * \param[in] s the index of the particle within the test block.
709 * \param[in] (x,y,z) The coordinates of the particle. */
710 template<class r_option>
711 template<class n_option>
712 bool container_base<r_option>::compute_cell_sphere(voronoicell_base<n_option> &c,int i,int j,int k,int ijk,int s,fpoint x,fpoint y,fpoint z) {
714 // This length scale determines how large the spherical shells should
715 // be, and it should be set to approximately the particle diameter
716 const fpoint length_scale=1;
717 fpoint x1,y1,z1,qx,qy,qz,lr=0,lrs=0,ur,urs,rs;
718 int q,t;
719 voropp_loop l(this);
720 if (!initialize_voronoicell(c,x,y,z)) return false;
722 // Now the cell is cut by testing neighboring particles in concentric
723 // shells. Once the test shell becomes twice as large as the Voronoi
724 // cell we can stop testing.
725 radius.init(ijk,s);
726 while(radius.cutoff(lrs)<c.maxradsq()) {
727 ur=lr+0.5*length_scale;urs=ur*ur;
728 t=l.init(x,y,z,ur,qx,qy,qz);
729 do {
730 for(q=0;q<co[t];q++) {
731 x1=p[t][sz*q]+qx-x;y1=p[t][sz*q+1]+qy-y;z1=p[t][sz*q+2]+qz-z;
732 rs=x1*x1+y1*y1+z1*z1;
733 if(lrs-tolerance<rs&&rs<urs&&(q!=s||ijk!=t)) {
734 if (!c.nplane(x1,y1,z1,radius.scale(rs,t,q),id[t][q])) return false;
737 } while((t=l.inc(qx,qy,qz))!=-1);
738 lr=ur;lrs=urs;
740 return true;
743 /** A overloaded version of compute_cell_sphere(), that sets up the x, y, and z
744 * variables.
745 * \param[in] &c a reference to a voronoicell object.
746 * \param[in] (i,j,k) the coordinates of the block that the test particle is
747 * in.
748 * \param[in] ijk the index of the block that the test particle is in, set to
749 * i+nx*(j+ny*k).
750 * \param[in] s the index of the particle within the test block. */
751 template<class r_option>
752 template<class n_option>
753 inline bool container_base<r_option>::compute_cell_sphere(voronoicell_base<n_option> &c,int i,int j,int k,int ijk,int s) {
754 fpoint x=p[ijk][sz*s],y=p[ijk][sz*s+1],z=p[ijk][sz*s+2];
755 return compute_cell_sphere(c,i,j,k,ijk,s,x,y,z);
758 /** A overloaded version of compute_cell, that sets up the x, y, and z variables.
759 * It can be run by the user, and it is also called multiple times by the
760 * functions print_all(), store_cell_volumes(), and the output routines.
761 * \param[in] &c a reference to a voronoicell object.
762 * \param[in] (i,j,k) the coordinates of the block that the test particle is
763 * in.
764 * \param[in] ijk the index of the block that the test particle is in, set to
765 * i+nx*(j+ny*k).
766 * \param[in] s the index of the particle within the test block. */
767 template<class r_option>
768 template<class n_option>
769 inline bool container_base<r_option>::compute_cell(voronoicell_base<n_option> &c,int i,int j,int k,int ijk,int s) {
770 fpoint x=p[ijk][sz*s],y=p[ijk][sz*s+1],z=p[ijk][sz*s+2];
771 return compute_cell(c,i,j,k,ijk,s,x,y,z);
774 /** This routine computes a Voronoi cell for a single particle in the
775 * container. It can be called by the user, but is also forms the core part of
776 * several of the main functions, such as store_cell_volumes(), print_all(),
777 * and the drawing routines. The algorithm constructs the cell by testing over
778 * the neighbors of the particle, working outwards until it reaches those
779 * particles which could not possibly intersect the cell. For maximum
780 * efficiency, this algorithm is divided into three parts. In the first
781 * section, the algorithm tests over the blocks which are in the immediate
782 * vicinity of the particle, by making use of one of the precomputed worklists.
783 * The code then continues to test blocks on the worklist, but also begins to
784 * construct a list of neighboring blocks outside the worklist which may need
785 * to be test. In the third section, the routine starts testing these
786 * neighboring blocks, evaluating whether or not a particle in them could
787 * possibly intersect the cell. For blocks that intersect the cell, it tests
788 * the particles in that block, and then adds the block neighbors to the list
789 * of potential places to consider.
790 * \param[in] &c a reference to a voronoicell object.
791 * \param[in] (i,j,k) the coordinates of the block that the test particle is
792 * in.
793 * \param[in] ijk the index of the block that the test particle is in, set to
794 * i+nx*(j+ny*k).
795 * \param[in] s the index of the particle within the test block.
796 * \param[in] (x,y,z) The coordinates of the particle.
797 * \param[in] s the index of the particle within the test block. */
798 template<class r_option>
799 template<class n_option>
800 bool container_base<r_option>::compute_cell(voronoicell_base<n_option> &c,int i,int j,int k,int ijk,int s,fpoint x,fpoint y,fpoint z) {
801 const fpoint boxx=(bx-ax)/nx,boxy=(by-ay)/ny,boxz=(bz-az)/nz;
802 fpoint x1,y1,z1,qx=0,qy=0,qz=0;
803 fpoint xlo,ylo,zlo,xhi,yhi,zhi,rs;
804 int ci,cj,ck,di,dj,dk,dijk,ei,ej,ek,eijk,si,sj,sk,sijk;
805 fpoint gxs,gys,gzs,*radp;
806 int f,g,l;unsigned int q,*e;
807 const unsigned int b1=1<<21,b2=1<<22,b3=1<<24,b4=1<<25,b5=1<<27,b6=1<<28;
809 radius.init(ijk,s);
811 // Initialize the Voronoi cell to fill the entire container
812 if (!initialize_voronoicell(c,x,y,z)) return false;
813 fpoint crs,mrs;
815 int next_count=3,list_index=0,list_size=8;
816 int count_list[]={7,11,15,19,26,35,45,59};
818 // Test all particles in the particle's local region first
819 for(l=0;l<s;l++) {
820 x1=p[ijk][sz*l]-x;
821 y1=p[ijk][sz*l+1]-y;
822 z1=p[ijk][sz*l+2]-z;
823 rs=radius.scale(x1*x1+y1*y1+z1*z1,ijk,l);
824 if (!c.nplane(x1,y1,z1,rs,id[ijk][l])) return false;
826 l++;
827 while(l<co[ijk]) {
828 x1=p[ijk][sz*l]-x;
829 y1=p[ijk][sz*l+1]-y;
830 z1=p[ijk][sz*l+2]-z;
831 rs=radius.scale(x1*x1+y1*y1+z1*z1,ijk,l);
832 if (!c.nplane(x1,y1,z1,rs,id[ijk][l])) return false;
833 l++;
836 // Now compute the maximum distance squared from the cell
837 // center to a vertex. This is used to cut off the calculation
838 // since we only need to test out to twice this range.
839 mrs=c.maxradsq();
841 // Now compute the fractional position of the particle within
842 // its region and store it in (fx,fy,fz). We use this to
843 // compute an index (si,sj,sk) of which subregion the particle
844 // is within.
845 unsigned int m1,m2;
846 fpoint fx=x-ax-boxx*i,fy=y-ay-boxy*j,fz=z-az-boxz*k;
847 si=int(fx*xsp*fgrid);sj=int(fy*ysp*fgrid);sk=int(fz*zsp*fgrid);
849 // The indices (si,sj,sk) tell us which worklist to use, to test the
850 // blocks in the optimal order. But we only store worklists for the
851 // eighth of the region where si, sj, and sk are all less than half the
852 // full grid. The rest of the cases are handled by symmetry. In this
853 // section, we detect for these cases, by reflecting high values of si,
854 // sj, and sk. For these cases, a mask is constructed in m1 and m2
855 // which is used to flip the worklist information when it is loaded.
856 if(si>=hgrid) {
857 gxs=fx;
858 m1=127+(3<<21);si=fgrid-1-si;m2=1+(1<<21);
859 } else {m1=m2=0;gxs=boxx-fx;}
860 if(sj>=hgrid) {
861 gys=fy;
862 m1|=(127<<7)+(3<<24);sj=fgrid-1-sj;m2|=(1<<7)+(1<<24);
863 } else gys=boxy-fy;
864 if(sk>=hgrid) {
865 gzs=fz;
866 m1|=(127<<14)+(3<<27);sk=fgrid-1-sk;m2|=(1<<14)+(1<<27);
867 } else gzs=boxz-fz;
868 gxs*=gxs;gys*=gys;gzs*=gzs;
870 // It's possible that a problem with the int() function could lead to
871 // spurious values with particles lying on the boundaries of the regions.
872 // In this section we correct for that.
873 if(si<0) si=0;if(sj<0) sj=0;if(sk<0) sk=0;
875 // Now compute which worklist we are going to use, and set radp and e to
876 // point at the right offsets
877 sijk=si+hgrid*(sj+hgrid*sk);
878 radp=mrad+sijk*seq_length;
879 e=(const_cast<unsigned int*> (wl))+sijk*seq_length;
881 // Read in how many items in the worklist can be tested without having to
882 // worry about writing to the mask
883 f=e[0];g=0;
884 do {
886 // At the intervals specified by count_list, we recompute the
887 // maximum radius squared
888 if(g==next_count) {
889 mrs=c.maxradsq();
890 if(list_index!=list_size) next_count=count_list[list_index++];
893 // If mrs is less than the minimum distance to any untested
894 // block, then we are done.
895 if(mrs<radius.cutoff(radp[g])) return true;
896 g++;
898 // Load in a block off the worklist, permute it with the
899 // symmetry mask, and decode its position. These are all
900 // integer bit operations so they should run very fast.
901 q=e[g];q^=m1;q+=m2;
902 di=q&127;di-=64;
903 dj=(q>>7)&127;dj-=64;
904 dk=(q>>14)&127;dk-=64;
906 // Check that the worklist position is in range
907 if(xperiodic) {if(di<-nx) continue;else if(di>nx) continue;}
908 else {if(di<-i) continue;else if(di>=nx-i) continue;}
909 if(yperiodic) {if(dj<-ny) continue;else if(dj>ny) continue;}
910 else {if(dj<-j) continue;else if(dj>=ny-j) continue;}
911 if(zperiodic) {if(dk<-nz) continue;else if(dk>nz) continue;}
912 else {if(dk<-k) continue;else if(dk>=nz-k) continue;}
914 // Call the compute_min_max_radius() function. This returns
915 // true if the minimum distance to the block is bigger than the
916 // current mrs, in which case we skip this block and move on.
917 // Otherwise, it computes the maximum distance to the block and
918 // returns it in crs.
919 if(compute_min_max_radius(di,dj,dk,fx,fy,fz,gxs,gys,gzs,crs,mrs)) continue;
921 // Now compute which region we are going to loop over, adding a
922 // displacement for the periodic cases.
923 di+=i;dj+=j;dk+=k;
924 if(xperiodic) {if(di<0) {qx=ax-bx;di+=nx;} else if(di>=nx) {qx=bx-ax;di-=nx;} else qx=0;}
925 if(yperiodic) {if(dj<0) {qy=ay-by;dj+=ny;} else if(dj>=ny) {qy=by-ay;dj-=ny;} else qy=0;}
926 if(zperiodic) {if(dk<0) {qz=az-bz;dk+=nz;} else if(dk>=nz) {qz=bz-az;dk-=nz;} else qz=0;}
927 dijk=di+nx*(dj+ny*dk);
929 // If mrs is bigger than the maximum distance to the block,
930 // then we have to test all particles in the block for
931 // intersections. Otherwise, we do additional checks and skip
932 // those particles which can't possibly intersect the block.
933 if(mrs>radius.cutoff(crs)) {
934 for(l=0;l<co[dijk];l++) {
935 x1=p[dijk][sz*l]+qx-x;
936 y1=p[dijk][sz*l+1]+qy-y;
937 z1=p[dijk][sz*l+2]+qz-z;
938 rs=radius.scale(x1*x1+y1*y1+z1*z1,dijk,l);
939 if (!c.nplane(x1,y1,z1,rs,id[dijk][l])) return false;
941 } else {
942 for(l=0;l<co[dijk];l++) {
943 x1=p[dijk][sz*l]+qx-x;
944 y1=p[dijk][sz*l+1]+qy-y;
945 z1=p[dijk][sz*l+2]+qz-z;
946 rs=radius.scale(x1*x1+y1*y1+z1*z1,dijk,l);
947 if(rs<mrs) {
948 if (!c.nplane(x1,y1,z1,rs,id[dijk][l])) return false;
952 } while(g<f);
954 // If we reach here, we were unable to compute the entire cell using
955 // the first part of the worklist. This section of the algorithm
956 // continues the worklist, but it now starts preparing the mask that we
957 // need if we end up going block by block. We do the same as before,
958 // but we put a mark down on the mask for every block that's tested.
959 // The worklist also contains information about which neighbors of each
960 // block are not also on the worklist, and we start storing those
961 // points in a list in case we have to go block by block.
962 ci=xperiodic?nx:i;
963 cj=yperiodic?ny:j;
964 ck=zperiodic?nz:k;
966 // Update the mask counter, and if it wraps around then reset the
967 // whole mask; that will only happen once every 2^32 tries
968 mv++;
969 if(mv==0) {
970 for(l=0;l<hxyz;l++) mask[l]=0;
971 mv=1;
974 // Reset the block by block counters
975 s_start=s_end=0;
977 while(g<seq_length-1) {
979 // At the intervals specified by count_list, we recompute the
980 // maximum radius squared
981 if(g==next_count) {
982 mrs=c.maxradsq();
983 if(list_index!=list_size) next_count=count_list[list_index++];
986 // If mrs is less than the minimum distance to any untested
987 // block, then we are done.
988 if(mrs<radius.cutoff(radp[g])) return true;
989 g++;
991 // Load in a block off the worklist, permute it with the
992 // symmetry mask, and decode its position. These are all
993 // integer bit operations so they should run very fast.
994 q=e[g];q^=m1;q+=m2;
995 di=q&127;di-=64;
996 dj=(q>>7)&127;dj-=64;
997 dk=(q>>14)&127;dk-=64;
999 // Compute the position in the mask of the current block. If
1000 // this lies outside the mask, then skip it. Otherwise, mark
1001 // it.
1002 ei=ci+di;
1003 ej=cj+dj;
1004 ek=ck+dk;
1005 if(ei<0) continue;else if(ei>=hx) continue;
1006 if(ej<0) continue;else if(ej>=hy) continue;
1007 if(ek<0) continue;else if(ek>=hz) continue;
1008 eijk=ei+hx*(ej+hy*ek);
1009 mask[eijk]=mv;
1011 // Call the compute_min_max_radius() function. This returns
1012 // true if the minimum distance to the block is bigger than the
1013 // current mrs, in which case we skip this block and move on.
1014 // Otherwise, it computes the maximum distance to the block and
1015 // returns it in crs.
1016 if(compute_min_max_radius(di,dj,dk,fx,fy,fz,gxs,gys,gzs,crs,mrs)) continue;
1018 // Now compute which region we are going to loop over, adding a
1019 // displacement for the periodic cases.
1020 di+=i;dj+=j;dk+=k;
1021 if(xperiodic) {if(di<0) {qx=ax-bx;di+=nx;} else if(di>=nx) {qx=bx-ax;di-=nx;} else qx=0;}
1022 if(yperiodic) {if(dj<0) {qy=ay-by;dj+=ny;} else if(dj>=ny) {qy=by-ay;dj-=ny;} else qy=0;}
1023 if(zperiodic) {if(dk<0) {qz=az-bz;dk+=nz;} else if(dk>=nz) {qz=bz-az;dk-=nz;} else qz=0;}
1024 dijk=di+nx*(dj+ny*dk);
1026 // If mrs is bigger than the maximum distance to the block,
1027 // then we have to test all particles in the block for
1028 // intersections. Otherwise, we do additional checks and skip
1029 // those particles which can't possibly intersect the block.
1030 if(mrs>radius.cutoff(crs)) {
1031 for(l=0;l<co[dijk];l++) {
1032 x1=p[dijk][sz*l]+qx-x;
1033 y1=p[dijk][sz*l+1]+qy-y;
1034 z1=p[dijk][sz*l+2]+qz-z;
1035 rs=radius.scale(x1*x1+y1*y1+z1*z1,dijk,l);
1036 if (!c.nplane(x1,y1,z1,rs,id[dijk][l])) return false;
1038 } else {
1039 for(l=0;l<co[dijk];l++) {
1040 x1=p[dijk][sz*l]+qx-x;
1041 y1=p[dijk][sz*l+1]+qy-y;
1042 z1=p[dijk][sz*l+2]+qz-z;
1043 rs=radius.scale(x1*x1+y1*y1+z1*z1,dijk,l);
1044 if(rs<mrs) {
1045 if(!c.nplane(x1,y1,z1,rs,id[dijk][l])) return false;
1050 // If there might not be enough memory on the list for these
1051 // additions, then add more
1052 if(s_end+18>s_size) add_list_memory();
1054 // Test the parts of the worklist element which tell us what
1055 // neighbors of this block are not on the worklist. Store them
1056 // on the block list, and mark the mask.
1057 if((q&b2)==b2) {
1058 if(ei>0) if(mask[eijk-1]!=mv) {mask[eijk-1]=mv;sl[s_end++]=ei-1;sl[s_end++]=ej;sl[s_end++]=ek;}
1059 if((q&b1)==0) if(ei<hx-1) if(mask[eijk+1]!=mv) {mask[eijk+1]=mv;sl[s_end++]=ei+1;sl[s_end++]=ej;sl[s_end++]=ek;}
1060 } else if((q&b1)==b1) {if(ei<hx-1) if(mask[eijk+1]!=mv) {mask[eijk+1]=mv;sl[s_end++]=ei+1;sl[s_end++]=ej;sl[s_end++]=ek;}}
1061 if((q&b4)==b4) {if(ej>0) if(mask[eijk-hx]!=mv) {mask[eijk-hx]=mv;sl[s_end++]=ei;sl[s_end++]=ej-1;sl[s_end++]=ek;}
1062 if((q&b3)==0) if(ej<hy-1) if(mask[eijk+hx]!=mv) {mask[eijk+hx]=mv;sl[s_end++]=ei;sl[s_end++]=ej+1;sl[s_end++]=ek;}
1063 } else if((q&b3)==b3) {if(ej<hy-1) if(mask[eijk+hx]!=mv) {mask[eijk+hx]=mv;sl[s_end++]=ei;sl[s_end++]=ej+1;sl[s_end++]=ek;}}
1064 if((q&b6)==b6) {if(ek>0) if(mask[eijk-hxy]!=mv) {mask[eijk-hxy]=mv;sl[s_end++]=ei;sl[s_end++]=ej;sl[s_end++]=ek-1;}
1065 if((q&b5)==0) if(ek<hz-1) if(mask[eijk+hxy]!=mv) {mask[eijk+hxy]=mv;sl[s_end++]=ei;sl[s_end++]=ej;sl[s_end++]=ek+1;}
1066 } else if((q&b5)==b5) if(ek<hz-1) if(mask[eijk+hxy]!=mv) {mask[eijk+hxy]=mv;sl[s_end++]=ei;sl[s_end++]=ej;sl[s_end++]=ek+1;}
1069 // Do a check to see if we've reach the radius cutoff
1070 if(mrs<radius.cutoff(radp[g])) return true;
1072 // Update the mask counter, and if it has wrapped around, then
1073 // reset the mask
1074 fx+=boxx*ci;fy+=boxy*cj;fz+=boxz*ck;
1076 // We were unable to completely compute the cell based on the blocks in
1077 // the worklist, so now we have to go block by block, reading in items
1078 // off the list
1079 while(s_start!=s_end) {
1081 // If we reached the end of the list memory loop back to the start
1082 if(s_start==s_size) s_start=0;
1084 // Read in a block off the list, and compute the upper and lower
1085 // coordinates in each of the three dimensions
1086 di=sl[s_start++];dj=sl[s_start++];dk=sl[s_start++];
1087 xlo=di*boxx-fx;xhi=xlo+boxx;
1088 ylo=dj*boxy-fy;yhi=ylo+boxy;
1089 zlo=dk*boxz-fz;zhi=zlo+boxz;
1091 // Carry out plane tests to see if any particle in this block
1092 // could possibly intersect the cell
1093 if(di>ci) {
1094 if(dj>cj) {
1095 if(dk>ck) {
1096 if(corner_test(c,xlo,ylo,zlo,xhi,yhi,zhi)) continue;
1097 } else if(dk<ck) {
1098 if(corner_test(c,xlo,ylo,zhi,xhi,yhi,zlo)) continue;
1099 } else {
1100 if(edge_z_test(c,xlo,ylo,zlo,xhi,yhi,zhi)) continue;
1102 } else if(dj<cj) {
1103 if(dk>ck) {
1104 if(corner_test(c,xlo,yhi,zlo,xhi,ylo,zhi)) continue;
1105 } else if(dk<ck) {
1106 if(corner_test(c,xlo,yhi,zhi,xhi,ylo,zlo)) continue;
1107 } else {
1108 if(edge_z_test(c,xlo,yhi,zlo,xhi,ylo,zhi)) continue;
1110 } else {
1111 if(dk>ck) {
1112 if(edge_y_test(c,xlo,ylo,zlo,xhi,yhi,zhi)) continue;
1113 } else if(dk<ck) {
1114 if(edge_y_test(c,xlo,ylo,zhi,xhi,yhi,zlo)) continue;
1115 } else {
1116 if(face_x_test(c,xlo,ylo,zlo,yhi,zhi)) continue;
1119 } else if(di<ci) {
1120 if(dj>cj) {
1121 if(dk>ck) {
1122 if(corner_test(c,xhi,ylo,zlo,xlo,yhi,zhi)) continue;
1123 } else if(dk<ck) {
1124 if(corner_test(c,xhi,ylo,zhi,xlo,yhi,zlo)) continue;
1125 } else {
1126 if(edge_z_test(c,xhi,ylo,zlo,xlo,yhi,zhi)) continue;
1128 } else if(dj<cj) {
1129 if(dk>ck) {
1130 if(corner_test(c,xhi,yhi,zlo,xlo,ylo,zhi)) continue;
1131 } else if(dk<ck) {
1132 if(corner_test(c,xhi,yhi,zhi,xlo,ylo,zlo)) continue;
1133 } else {
1134 if(edge_z_test(c,xhi,yhi,zlo,xlo,ylo,zhi)) continue;
1136 } else {
1137 if(dk>ck) {
1138 if(edge_y_test(c,xhi,ylo,zlo,xlo,yhi,zhi)) continue;
1139 } else if(dk<ck) {
1140 if(edge_y_test(c,xhi,ylo,zhi,xlo,yhi,zlo)) continue;
1141 } else {
1142 if(face_x_test(c,xhi,ylo,zlo,yhi,zhi)) continue;
1145 } else {
1146 if(dj>cj) {
1147 if(dk>ck) {
1148 if(edge_x_test(c,xlo,ylo,zlo,xhi,yhi,zhi)) continue;
1149 } else if(dk<ck) {
1150 if(edge_x_test(c,xlo,ylo,zhi,xhi,yhi,zlo)) continue;
1151 } else {
1152 if(face_y_test(c,xlo,ylo,zlo,xhi,zhi)) continue;
1154 } else if(dj<cj) {
1155 if(dk>ck) {
1156 if(edge_x_test(c,xlo,yhi,zlo,xhi,ylo,zhi)) continue;
1157 } else if(dk<ck) {
1158 if(edge_x_test(c,xlo,yhi,zhi,xhi,ylo,zlo)) continue;
1159 } else {
1160 if(face_y_test(c,xlo,yhi,zlo,xhi,zhi)) continue;
1162 } else {
1163 if(dk>ck) {
1164 if(face_z_test(c,xlo,ylo,zlo,xhi,yhi)) continue;
1165 } else if(dk<ck) {
1166 if(face_z_test(c,xlo,ylo,zhi,xhi,yhi)) continue;
1167 } else {
1168 cout << "Can't happen ... happened\n";
1173 // Now compute the region that we are going to test over, and
1174 // set a displacement vector for the periodic cases.
1175 if(xperiodic) {ei=i+di-nx;if(ei<0) {qx=ax-bx;ei+=nx;} else if(ei>=nx) {qx=bx-ax;ei-=nx;} else qx=0;} else ei=di;
1176 if(yperiodic) {ej=j+dj-ny;if(ej<0) {qy=ay-by;ej+=ny;} else if(ej>=ny) {qy=by-ay;ej-=ny;} else qy=0;} else ej=dj;
1177 if(zperiodic) {ek=k+dk-nz;if(ek<0) {qz=az-bz;ek+=nz;} else if(ek>=nz) {qz=bz-az;ek-=nz;} else qz=0;} else ek=dk;
1178 eijk=ei+nx*(ej+ny*ek);
1180 // Loop over all the elements in the block to test for cuts.
1181 // It would be possible to exclude some of these cases by testing
1182 // against mrs, but I am not convinced that this will save time.
1183 for(l=0;l<co[eijk];l++) {
1184 x1=p[eijk][sz*l]+qx-x;
1185 y1=p[eijk][sz*l+1]+qy-y;
1186 z1=p[eijk][sz*l+2]+qz-z;
1187 rs=radius.scale(x1*x1+y1*y1+z1*z1,eijk,l);
1188 if (!c.nplane(x1,y1,z1,rs,id[eijk][l])) return false;
1191 // If there's not much memory on the block list then add more
1192 if((s_start<=s_end?s_size-s_end+s_start:s_end-s_start)<18) add_list_memory();
1194 // Test the neighbors of the current block, and add them to the
1195 // block list if they haven't already been tested.
1196 dijk=di+hx*(dj+hy*dk);
1197 if(di>0) if(mask[dijk-1]!=mv) {if(s_end==s_size) s_end=0;mask[dijk-1]=mv;sl[s_end++]=di-1;sl[s_end++]=dj;sl[s_end++]=dk;}
1198 if(dj>0) if(mask[dijk-hx]!=mv) {if(s_end==s_size) s_end=0;mask[dijk-hx]=mv;sl[s_end++]=di;sl[s_end++]=dj-1;sl[s_end++]=dk;}
1199 if(dk>0) if(mask[dijk-hxy]!=mv) {if(s_end==s_size) s_end=0;mask[dijk-hxy]=mv;sl[s_end++]=di;sl[s_end++]=dj;sl[s_end++]=dk-1;}
1200 if(di<hx-1) if(mask[dijk+1]!=mv) {if(s_end==s_size) s_end=0;mask[dijk+1]=mv;sl[s_end++]=di+1;sl[s_end++]=dj;sl[s_end++]=dk;}
1201 if(dj<hy-1) if(mask[dijk+hx]!=mv) {if(s_end==s_size) s_end=0;mask[dijk+hx]=mv;sl[s_end++]=di;sl[s_end++]=dj+1;sl[s_end++]=dk;}
1202 if(dk<hz-1) if(mask[dijk+hxy]!=mv) {if(s_end==s_size) s_end=0;mask[dijk+hxy]=mv;sl[s_end++]=di;sl[s_end++]=dj;sl[s_end++]=dk+1;}
1205 return true;
1208 /** This function checks to see whether a particular block can possibly have
1209 * any intersection with a Voronoi cell, for the case when the closest point
1210 * from the cell center to the block is at a corner.
1211 * \param[in] &c a reference to a Voronoi cell.
1212 * \param[in] (xl,yl,zl) the relative coordinates of the corner of the block closest to
1213 * the cell center.
1214 * \param[in] (xh,yh,zh) the relative coordinates of the corner of the block furthest
1215 * away from the cell center.
1216 * \return false if the block may intersect, true if does not. */
1217 template<class r_option>
1218 template<class n_option>
1219 inline bool container_base<r_option>::corner_test(voronoicell_base<n_option> &c,fpoint xl,fpoint yl,fpoint zl,fpoint xh,fpoint yh,fpoint zh) {
1220 if(c.plane_intersects_guess(xh,yl,zl,radius.cutoff(xl*xh+yl*yl+zl*zl))) return false;
1221 if(c.plane_intersects(xh,yh,zl,radius.cutoff(xl*xh+yl*yh+zl*zl))) return false;
1222 if(c.plane_intersects(xl,yh,zl,radius.cutoff(xl*xl+yl*yh+zl*zl))) return false;
1223 if(c.plane_intersects(xl,yh,zh,radius.cutoff(xl*xl+yl*yh+zl*zh))) return false;
1224 if(c.plane_intersects(xl,yl,zh,radius.cutoff(xl*xl+yl*yl+zl*zh))) return false;
1225 if(c.plane_intersects(xh,yl,zh,radius.cutoff(xl*xh+yl*yl+zl*zh))) return false;
1226 return true;
1229 /** This function checks to see whether a particular block can possibly have
1230 * any intersection with a Voronoi cell, for the case when the closest point
1231 * from the cell center to the block is on an edge which points along the x
1232 * direction.
1233 * \param[in] &c a reference to a Voronoi cell.
1234 * \param[in] (x0,x1) the minimum and maximum relative x coordinates of the block.
1235 * \param[in] (yl,zl) the relative y and z coordinates of the corner of the block closest to
1236 * the cell center.
1237 * \param[in] (yh,zh) the relative y and z coordinates of the corner of the block furthest
1238 * away from the cell center.
1239 * \return false if the block may intersect, true if does not. */
1240 template<class r_option>
1241 template<class n_option>
1242 inline bool container_base<r_option>::edge_x_test(voronoicell_base<n_option> &c,fpoint x0,fpoint yl,fpoint zl,fpoint x1,fpoint yh,fpoint zh) {
1243 if(c.plane_intersects_guess(x0,yl,zh,radius.cutoff(yl*yl+zl*zh))) return false;
1244 if(c.plane_intersects(x1,yl,zh,radius.cutoff(yl*yl+zl*zh))) return false;
1245 if(c.plane_intersects(x1,yl,zl,radius.cutoff(yl*yl+zl*zl))) return false;
1246 if(c.plane_intersects(x0,yl,zl,radius.cutoff(yl*yl+zl*zl))) return false;
1247 if(c.plane_intersects(x0,yh,zl,radius.cutoff(yl*yh+zl*zl))) return false;
1248 if(c.plane_intersects(x1,yh,zl,radius.cutoff(yl*yh+zl*zl))) return false;
1249 return true;
1252 /** This function checks to see whether a particular block can possibly have
1253 * any intersection with a Voronoi cell, for the case when the closest point
1254 * from the cell center to the block is on an edge which points along the y
1255 * direction.
1256 * \param[in] &c a reference to a Voronoi cell.
1257 * \param[in] (y0,y1) the minimum and maximum relative y coordinates of the block.
1258 * \param[in] (xl,zl) the relative x and z coordinates of the corner of the block closest to
1259 * the cell center.
1260 * \param[in] (xh,zh) the relative x and z coordinates of the corner of the block furthest
1261 * away from the cell center.
1262 * \return false if the block may intersect, true if does not. */
1263 template<class r_option>
1264 template<class n_option>
1265 inline bool container_base<r_option>::edge_y_test(voronoicell_base<n_option> &c,fpoint xl,fpoint y0,fpoint zl,fpoint xh,fpoint y1,fpoint zh) {
1266 if(c.plane_intersects_guess(xl,y0,zh,radius.cutoff(xl*xl+zl*zh))) return false;
1267 if(c.plane_intersects(xl,y1,zh,radius.cutoff(xl*xl+zl*zh))) return false;
1268 if(c.plane_intersects(xl,y1,zl,radius.cutoff(xl*xl+zl*zl))) return false;
1269 if(c.plane_intersects(xl,y0,zl,radius.cutoff(xl*xl+zl*zl))) return false;
1270 if(c.plane_intersects(xh,y0,zl,radius.cutoff(xl*xh+zl*zl))) return false;
1271 if(c.plane_intersects(xh,y1,zl,radius.cutoff(xl*xh+zl*zl))) return false;
1272 return true;
1275 /** This function checks to see whether a particular block can possibly have
1276 * any intersection with a Voronoi cell, for the case when the closest point
1277 * from the cell center to the block is on an edge which points along the z
1278 * direction.
1279 * \param[in] &c a reference to a Voronoi cell.
1280 * \param[in] (z0,z1) the minimum and maximum relative z coordinates of the block.
1281 * \param[in] (xl,yl) the relative x and y coordinates of the corner of the block closest to
1282 * the cell center.
1283 * \param[in] (xh,yh) the relative x and y coordinates of the corner of the block furthest
1284 * away from the cell center.
1285 * \return false if the block may intersect, true if does not. */
1286 template<class r_option>
1287 template<class n_option>
1288 inline bool container_base<r_option>::edge_z_test(voronoicell_base<n_option> &c,fpoint xl,fpoint yl,fpoint z0,fpoint xh,fpoint yh,fpoint z1) {
1289 if(c.plane_intersects_guess(xl,yh,z0,radius.cutoff(xl*xl+yl*yh))) return false;
1290 if(c.plane_intersects(xl,yh,z1,radius.cutoff(xl*xl+yl*yh))) return false;
1291 if(c.plane_intersects(xl,yl,z1,radius.cutoff(xl*xl+yl*yl))) return false;
1292 if(c.plane_intersects(xl,yl,z0,radius.cutoff(xl*xl+yl*yl))) return false;
1293 if(c.plane_intersects(xh,yl,z0,radius.cutoff(xl*xh+yl*yl))) return false;
1294 if(c.plane_intersects(xh,yl,z1,radius.cutoff(xl*xh+yl*yl))) return false;
1295 return true;
1298 /** This function checks to see whether a particular block can possibly have
1299 * any intersection with a Voronoi cell, for the case when the closest point
1300 * from the cell center to the block is on a face aligned with the x direction.
1301 * \param[in] &c a reference to a Voronoi cell.
1302 * \param[in] xl the minimum distance from the cell center to the face.
1303 * \param[in] (y0,y1) the minimum and maximum relative y coordinates of the block.
1304 * \param[in] (z0,z1) the minimum and maximum relative z coordinates of the block.
1305 * \return false if the block may intersect, true if does not. */
1306 template<class r_option>
1307 template<class n_option>
1308 inline bool container_base<r_option>::face_x_test(voronoicell_base<n_option> &c,fpoint xl,fpoint y0,fpoint z0,fpoint y1,fpoint z1) {
1309 if(c.plane_intersects_guess(xl,y0,z0,radius.cutoff(xl*xl))) return false;
1310 if(c.plane_intersects(xl,y0,z1,radius.cutoff(xl*xl))) return false;
1311 if(c.plane_intersects(xl,y1,z1,radius.cutoff(xl*xl))) return false;
1312 if(c.plane_intersects(xl,y1,z0,radius.cutoff(xl*xl))) return false;
1313 return true;
1316 /** This function checks to see whether a particular block can possibly have
1317 * any intersection with a Voronoi cell, for the case when the closest point
1318 * from the cell center to the block is on a face aligned with the y direction.
1319 * \param[in] &c a reference to a Voronoi cell.
1320 * \param[in] yl the minimum distance from the cell center to the face.
1321 * \param[in] (x0,x1) the minimum and maximum relative x coordinates of the block.
1322 * \param[in] (z0,z1) the minimum and maximum relative z coordinates of the block.
1323 * \return false if the block may intersect, true if does not. */
1324 template<class r_option>
1325 template<class n_option>
1326 inline bool container_base<r_option>::face_y_test(voronoicell_base<n_option> &c,fpoint x0,fpoint yl,fpoint z0,fpoint x1,fpoint z1) {
1327 if(c.plane_intersects_guess(x0,yl,z0,radius.cutoff(yl*yl))) return false;
1328 if(c.plane_intersects(x0,yl,z1,radius.cutoff(yl*yl))) return false;
1329 if(c.plane_intersects(x1,yl,z1,radius.cutoff(yl*yl))) return false;
1330 if(c.plane_intersects(x1,yl,z0,radius.cutoff(yl*yl))) return false;
1331 return true;
1334 /** This function checks to see whether a particular block can possibly have
1335 * any intersection with a Voronoi cell, for the case when the closest point
1336 * from the cell center to the block is on a face aligned with the z direction.
1337 * \param[in] &c a reference to a Voronoi cell.
1338 * \param[in] zl the minimum distance from the cell center to the face.
1339 * \param[in] (x0,x1) the minimum and maximum relative x coordinates of the block.
1340 * \param[in] (y0,y1) the minimum and maximum relative y coordinates of the block.
1341 * \return false if the block may intersect, true if does not. */
1342 template<class r_option>
1343 template<class n_option>
1344 inline bool container_base<r_option>::face_z_test(voronoicell_base<n_option> &c,fpoint x0,fpoint y0,fpoint zl,fpoint x1,fpoint y1) {
1345 if(c.plane_intersects_guess(x0,y0,zl,radius.cutoff(zl*zl))) return false;
1346 if(c.plane_intersects(x0,y1,zl,radius.cutoff(zl*zl))) return false;
1347 if(c.plane_intersects(x1,y1,zl,radius.cutoff(zl*zl))) return false;
1348 if(c.plane_intersects(x1,y0,zl,radius.cutoff(zl*zl))) return false;
1349 return true;
1352 /** Creates a voropp_loop object, by pulling the necessary constants about the container
1353 * geometry from a pointer to the current container class. */
1354 template<class r_option>
1355 voropp_loop::voropp_loop(container_base<r_option> *q) : sx(q->bx-q->ax), sy(q->by-q->ay), sz(q->bz-q->az),
1356 xsp(q->xsp),ysp(q->ysp),zsp(q->zsp),
1357 ax(q->ax),ay(q->ay),az(q->az),
1358 nx(q->nx),ny(q->ny),nz(q->nz),nxy(q->nxy),nxyz(q->nxyz),
1359 xperiodic(q->xperiodic),yperiodic(q->yperiodic),zperiodic(q->zperiodic) {}
1361 /** Initializes a voropp_loop object, by finding all blocks which are within a distance
1362 * r of the vector (vx,vy,vz). It returns the first block which is to be
1363 * tested, and sets the periodic displacement vector (px,py,pz) accordingly. */
1364 inline int voropp_loop::init(fpoint vx,fpoint vy,fpoint vz,fpoint r,fpoint &px,fpoint &py,fpoint &pz) {
1365 ai=step_int((vx-ax-r)*xsp);
1366 bi=step_int((vx-ax+r)*xsp);
1367 if(!xperiodic) {
1368 if(ai<0) {ai=0;if(bi<0) bi=0;}
1369 if(bi>=nx) {bi=nx-1;if(ai>=nx) ai=nx-1;}
1371 aj=step_int((vy-ay-r)*ysp);
1372 bj=step_int((vy-ay+r)*ysp);
1373 if(!yperiodic) {
1374 if(aj<0) {aj=0;if(bj<0) bj=0;}
1375 if(bj>=ny) {bj=ny-1;if(aj>=ny) aj=ny-1;}
1377 ak=step_int((vz-az-r)*zsp);
1378 bk=step_int((vz-az+r)*zsp);
1379 if(!zperiodic) {
1380 if(ak<0) {ak=0;if(bk<0) bk=0;}
1381 if(bk>=nz) {bk=nz-1;if(ak>=nz) ak=nz-1;}
1383 i=ai;j=aj;k=ak;
1384 aip=ip=step_mod(i,nx);apx=px=step_div(i,nx)*sx;
1385 ajp=jp=step_mod(j,ny);apy=py=step_div(j,ny)*sy;
1386 akp=kp=step_mod(k,nz);apz=pz=step_div(k,nz)*sz;
1387 inc1=aip-step_mod(bi,nx);
1388 inc2=nx*(ny+ajp-step_mod(bj,ny))+inc1;
1389 inc1+=nx;
1390 s=aip+nx*(ajp+ny*akp);
1391 return s;
1394 /** Initializes a voropp_loop object, by finding all blocks which overlap the box with
1395 * corners (xmin,ymin,zmin) and (xmax,ymax,zmax). It returns the first block
1396 * which is to be tested, and sets the periodic displacement vector (px,py,pz)
1397 * accordingly. */
1398 inline int voropp_loop::init(fpoint xmin,fpoint xmax,fpoint ymin,fpoint ymax,fpoint zmin,fpoint zmax,fpoint &px,fpoint &py,fpoint &pz) {
1399 ai=step_int((xmin-ax)*xsp);
1400 bi=step_int((xmax-ax)*xsp);
1401 if(!xperiodic) {
1402 if(ai<0) {ai=0;if(bi<0) bi=0;}
1403 if(bi>=nx) {bi=nx-1;if(ai>=nx) ai=nx-1;}
1405 aj=step_int((ymin-ay)*ysp);
1406 bj=step_int((ymax-ay)*ysp);
1407 if(!yperiodic) {
1408 if(aj<0) {aj=0;if(bj<0) bj=0;}
1409 if(bj>=ny) {bj=ny-1;if(aj>=ny) aj=ny-1;}
1411 ak=step_int((zmin-az)*zsp);
1412 bk=step_int((zmax-az)*zsp);
1413 if(!zperiodic) {
1414 if(ak<0) {ak=0;if(bk<0) bk=0;}
1415 if(bk>=nz) {bk=nz-1;if(ak>=nz) ak=nz-1;}
1417 aip=step_mod(ai,nx);apx=step_div(ai,nx)*sx;
1418 ajp=step_mod(aj,ny);apy=step_div(aj,ny)*sy;
1419 akp=step_mod(ak,nz);apz=step_div(ak,nz)*sz;
1420 inc1=aip-step_mod(bi,nx);
1421 inc2=nx*(ny+ajp-step_mod(bj,ny))+inc1;
1422 inc1+=nx;
1423 return reset(px,py,pz);
1426 inline int voropp_loop::reset(fpoint &px,fpoint &py,fpoint &pz) {
1427 i=ai;j=aj;k=ak;
1428 ip=aip;jp=ajp;kp=akp;
1429 px=apx;py=apy;pz=apz;
1430 s=aip+nx*(ajp+ny*akp);
1431 return s;
1434 /** Returns the next block to be tested in a loop, and updates the periodicity
1435 * vector if necessary. */
1436 inline int voropp_loop::inc(fpoint &px,fpoint &py,fpoint &pz) {
1437 if(i<bi) {
1438 i++;
1439 if(ip<nx-1) {ip++;s++;} else {ip=0;s+=1-nx;px+=sx;}
1440 return s;
1441 } else if(j<bj) {
1442 i=ai;ip=aip;px=apx;j++;
1443 if(jp<ny-1) {jp++;s+=inc1;} else {jp=0;s+=inc1-nxy;py+=sy;}
1444 return s;
1445 } else if(k<bk) {
1446 i=ai;ip=aip;j=aj;jp=ajp;px=apx;py=apy;k++;
1447 if(kp<nz-1) {kp++;s+=inc2;} else {kp=0;s+=inc2-nxyz;pz+=sz;}
1448 return s;
1449 } else return -1;
1452 inline bool voropp_loop::reached(int ri,int rj,int rk) {
1453 return rk==k&&rj==j&&ri==i;
1456 /** Custom int function, that gives consistent stepping for negative numbers.
1457 * With normal int, we have (-1.5,-0.5,0.5,1.5) -> (-1,0,0,1).
1458 * With this routine, we have (-1.5,-0.5,0.5,1.5) -> (-2,-1,0,1).*/
1459 inline int voropp_loop::step_int(fpoint a) {
1460 return a<0?int(a)-1:int(a);
1463 /** Custom mod function, that gives consistent stepping for negative numbers. */
1464 inline int voropp_loop::step_mod(int a,int b) {
1465 return a>=0?a%b:b-1-(b-1-a)%b;
1468 /** Custom div function, that gives consistent stepping for negative numbers. */
1469 inline int voropp_loop::step_div(int a,int b) {
1470 return a>=0?a/b:-1+(a+1)/b;
1473 /** Adds a wall to the container.
1474 * \param[in] &w a wall object to be added.*/
1475 template<class r_option>
1476 void container_base<r_option>::add_wall(wall& w) {
1477 if(wall_number==current_wall_size) {
1478 current_wall_size*=2;
1479 if(current_wall_size>max_wall_size) throw fatal_error("Wall memory allocation exceeded absolute maximum");
1480 wall **pwall;
1481 pwall=new wall*[current_wall_size];
1482 for(int i=0;i<wall_number;i++) pwall[i]=walls[i];
1483 delete [] walls;walls=pwall;
1485 walls[wall_number++]=&w;
1488 /** Sets the radius of the jth particle in region i to r, and updates the maximum particle radius.
1489 * \param[in] i the region of the particle to consider.
1490 * \param[in] j the number of the particle within the region.
1491 * \param[in] r the radius to set. */
1492 inline void radius_poly::store_radius(int i,int j,fpoint r) {
1493 cc->p[i][4*j+3]=r;
1494 if(r>max_radius) max_radius=r;
1497 /** Clears the stored maximum radius. */
1498 inline void radius_poly::clear_max() {
1499 max_radius=0;
1502 /** Imports a list of particles from an input stream of a LAMMPS restart file
1503 * for the monodisperse case where no radius information is expected.
1504 * \param[in] &is an input stream to read from. */
1505 inline void radius_mono::import_lammps(istream &is,int n,bool scaled) {
1506 const fpoint ax=cc->ax,ay=cc->ay,az=cc->az;
1507 const fpoint facx=cc->bx-ax,facy=cc->by-ay,facz=cc->bz-az;
1508 fpoint j,t,d,x,y,z;
1509 for(int i=0;i<n;i++) {
1510 is >> j >> t >> d >> x >> y >> z;
1511 if(scaled) {x=x*facx+ax;y=y*facy+ay;z=z*facz+az;}
1512 cc->put(j,x,y,z);
1516 /** Imports a list of particles from an input stream of a LAMMPS restart file
1517 * for the polydisperse case, where both positions and particle radii are both stored.
1518 * \param[in] &is an input stream to read from. */
1519 inline void radius_poly::import_lammps(istream &is,int n,bool scaled) {
1520 const fpoint ax=cc->ax,ay=cc->ay,az=cc->az;
1521 const fpoint facx=cc->bx-ax,facy=cc->by-ay,facz=cc->bz-az;
1522 fpoint j,t,d,x,y,z;
1523 for(int i=0;i<n;i++) {
1524 is >> j >> t >> d >> x >> y >> z;d*=0.5;
1525 if(scaled) {x=x*facx+ax;y=y*facy+ay;z=z*facz+az;}
1526 cc->put(j,x,y,z,d);
1530 /** Imports a list of particles from an input stream for the monodisperse case
1531 * where no radius information is expected.
1532 * \param[in] &is an input stream to read from. */
1533 inline void radius_mono::import(istream &is) {
1534 int n;fpoint x,y,z;
1535 is >> n >> x >> y >> z;
1536 while(!is.eof()) {
1537 cc->put(n,x,y,z);
1538 is >> n >> x >> y >> z;
1542 /** Imports a list of particles from an input stream for the polydisperse case,
1543 * where both positions and particle radii are both stored.
1544 * \param[in] &is an input stream to read from. */
1545 inline void radius_poly::import(istream &is) {
1546 int n;fpoint x,y,z,r;
1547 is >> n >> x >> y >> z >> r;
1548 while(!is.eof()) {
1549 cc->put(n,x,y,z,r);
1550 is >> n >> x >> y >> z >> r;
1554 /** Initializes the radius_poly class for a new Voronoi cell calculation,
1555 * by computing the radial cut-off value, based on the current particle's
1556 * radius and the maximum radius of any particle in the packing.
1557 * \param[in] ijk the region to consider.
1558 * \param[in] s the number of the particle within the region. */
1559 inline void radius_poly::init(int ijk,int s) {
1560 crad=cc->p[ijk][4*s+3];
1561 mul=1+(crad*crad-max_radius*max_radius)/((max_radius+crad)*(max_radius+crad));
1562 crad*=crad;
1565 /** This routine is called when deciding when to terminate the computation
1566 * of a Voronoi cell. For the Voronoi radical tessellation for a polydisperse
1567 * case, this routine multiplies the cutoff value by the scaling factor that
1568 * was precomputed in the init() routine.
1569 * \param[in] lrs a cutoff radius for the cell computation.
1570 * \return The value scaled by the factor mul. */
1571 inline fpoint radius_poly::cutoff(fpoint lrs) {
1572 return mul*lrs;
1575 /** This routine is called when deciding when to terminate the computation
1576 * of a Voronoi cell. For the monodisperse case, this routine just returns
1577 * the same value that is passed to it.
1578 * \param[in] lrs a cutoff radius for the cell computation.
1579 * \return The same value passed to it. */
1580 inline fpoint radius_mono::cutoff(fpoint lrs) {
1581 return lrs;
1584 /** Prints the diameter of a particle as 1 during the LAMMPS snapshot output, a
1585 * generic value for the monodisperse case.
1586 * \param[in] &os the output stream to write to.
1587 * \param[in] l the region to consider.
1588 * \param[in] c the number of the particle within the region. */
1589 inline void radius_mono::diam(ostream &os,int l,int c) {
1590 os << "1";
1593 /** Prints the diameter of a particle during the LAMMPS snapshot output.
1594 * \param[in] &os the output stream to write to.
1595 * \param[in] l the region to consider.
1596 * \param[in] c the number of the particle within the region. */
1597 inline void radius_poly::diam(ostream &os,int l,int c) {
1598 os << cc->p[l][4*c+3];
1601 /** Prints the radius of particle, by just supplying a generic value of "s".
1602 * \param[in] &os the output stream to write to.
1603 * \param[in] l the region to consider.
1604 * \param[in] c the number of the particle within the region. */
1605 inline void radius_mono::rad(ostream &os,int l,int c) {
1606 os << "s";
1609 /** Prints the radius of a particle to an open output stream.
1610 * \param[in] &os the output stream to write to.
1611 * \param[in] l the region to consider.
1612 * \param[in] c the number of the particle within the region. */
1613 inline void radius_poly::rad(ostream &os,int l,int c) {
1614 os << cc->p[l][4*c+3];
1617 /** Returns the scaled volume of a particle, which is always set
1618 * to 0.125 for the monodisperse case where particles are taken
1619 * to have unit diameter.
1620 * \param[in] ijk the region to consider.
1621 * \param[in] s the number of the particle within the region.
1622 * \return The cube of the radius of the particle, which is 0.125
1623 * in this case. */
1624 inline fpoint radius_mono::volume(int ijk,int s) {
1625 return 0.125;
1628 /** Returns the scaled volume of a particle.
1629 * \param[in] ijk the region to consider.
1630 * \param[in] s the number of the particle within the region.
1631 * \return The cube of the radius of the particle. */
1632 inline fpoint radius_poly::volume(int ijk,int s) {
1633 fpoint a=cc->p[ijk][4*s+3];
1634 return a*a*a;
1637 /** Scales the position of a plane according to the relative sizes
1638 * of the particle radii.
1639 * \param[in] rs the distance between the Voronoi cell and the cutting plane.
1640 * \param[in] t the region to consider
1641 * \param[in] q the number of the particle within the region.
1642 * \return The scaled position. */
1643 inline fpoint radius_poly::scale(fpoint rs,int t,int q) {
1644 return rs+crad-cc->p[t][4*q+3]*cc->p[t][4*q+3];
1647 /** Applies a blank scaling to the position of a cutting plane.
1648 * \param[in] rs the distance between the Voronoi cell and the cutting plane.
1649 * \param[in] t the region to consider
1650 * \param[in] q the number of the particle within the region.
1651 * \return The scaled position, which for this case, is equal to rs. */
1652 inline fpoint radius_mono::scale(fpoint rs,int t,int q) {
1653 return rs;
1656 /** Prints the radius of a particle to an open file stream.
1657 * \param[in] &os an open file stream.
1658 * \param[in] ijk the region to consider.
1659 * \param[in] q the number of the particle within the region. */
1660 inline void radius_poly::print(ostream &os,int ijk,int q) {
1661 os << " " << cc->p[ijk][4*q+3];
1664 /** This routine checks to see whether a point is within a particular distance
1665 * of a nearby region. If the point is within the distance of the region, then
1666 * the routine returns true, and computes the maximum distance from the point
1667 * to the region. Otherwise, the routine returns false.
1668 * \param[in] (di,dj,dk) The position of the nearby region to be tested,
1669 * relative to the region that the point is in.
1670 * \param[in] (fx,fy,fz) The displacement of the point within its region.
1671 * \param[in] (gxs,gys,gzs) The minimum squared distances from the point to the
1672 * sides of its region.
1673 * \param[in] &crs A reference in which to return the maximum distance to the
1674 * region (only computed if the routine returns positive).
1675 * \param[in] mrs The distance to be tested.
1676 * \return False if the region is further away than mrs, true if the region in within mrs.*/
1677 template<class r_option>
1678 inline bool container_base<r_option>::compute_min_max_radius(int di,int dj,int dk,fpoint fx,fpoint fy,fpoint fz,fpoint gxs,fpoint gys,fpoint gzs,fpoint &crs,fpoint mrs) {
1679 fpoint xlo,ylo,zlo;
1680 const fpoint boxx=(bx-ax)/nx,boxy=(by-ay)/ny,boxz=(bz-az)/nz;
1681 const fpoint bxsq=boxx*boxx+boxy*boxy+boxz*boxz;
1682 if(di>0) {
1683 xlo=di*boxx-fx;
1684 crs=xlo*xlo;
1685 if(dj>0) {
1686 ylo=dj*boxy-fy;
1687 crs+=ylo*ylo;
1688 if(dk>0) {
1689 zlo=dk*boxz-fz;
1690 crs+=zlo*zlo;if(radius.cutoff(crs)>mrs) return true;
1691 crs+=bxsq+2*(boxx*xlo+boxy*ylo+boxz*zlo);
1692 } else if(dk<0) {
1693 zlo=(dk+1)*boxz-fz;
1694 crs+=zlo*zlo;if(radius.cutoff(crs)>mrs) return true;
1695 crs+=bxsq+2*(boxx*xlo+boxy*ylo-boxz*zlo);
1696 } else {
1697 if(radius.cutoff(crs)>mrs) return true;
1698 crs+=boxx*(2*xlo+boxx)+boxy*(2*ylo+boxy)+gzs;
1700 } else if(dj<0) {
1701 ylo=(dj+1)*boxy-fy;
1702 crs+=ylo*ylo;
1703 if(dk>0) {
1704 zlo=dk*boxz-fz;
1705 crs+=zlo*zlo;if(radius.cutoff(crs)>mrs) return true;
1706 crs+=bxsq+2*(boxx*xlo-boxy*ylo+boxz*zlo);
1707 } else if(dk<0) {
1708 zlo=(dk+1)*boxz-fz;
1709 crs+=zlo*zlo;if(radius.cutoff(crs)>mrs) return true;
1710 crs+=bxsq+2*(boxx*xlo-boxy*ylo-boxz*zlo);
1711 } else {
1712 if(radius.cutoff(crs)>mrs) return true;
1713 crs+=boxx*(2*xlo+boxx)+boxy*(-2*ylo+boxy)+gzs;
1715 } else {
1716 if(dk>0) {
1717 zlo=dk*boxz-fz;
1718 crs+=zlo*zlo;if(radius.cutoff(crs)>mrs) return true;
1719 crs+=boxz*(2*zlo+boxz);
1720 } else if(dk<0) {
1721 zlo=(dk+1)*boxz-fz;
1722 crs+=zlo*zlo;if(radius.cutoff(crs)>mrs) return true;
1723 crs+=boxz*(-2*zlo+boxz);
1724 } else {
1725 if(radius.cutoff(crs)>mrs) return true;
1726 crs+=gzs;
1728 crs+=gys+boxx*(2*xlo+boxx);
1730 } else if(di<0) {
1731 xlo=(di+1)*boxx-fx;
1732 crs=xlo*xlo;
1733 if(dj>0) {
1734 ylo=dj*boxy-fy;
1735 crs+=ylo*ylo;
1736 if(dk>0) {
1737 zlo=dk*boxz-fz;
1738 crs+=zlo*zlo;if(radius.cutoff(crs)>mrs) return true;
1739 crs+=bxsq+2*(-boxx*xlo+boxy*ylo+boxz*zlo);
1740 } else if(dk<0) {
1741 zlo=(dk+1)*boxz-fz;
1742 crs+=zlo*zlo;if(radius.cutoff(crs)>mrs) return true;
1743 crs+=bxsq+2*(-boxx*xlo+boxy*ylo-boxz*zlo);
1744 } else {
1745 if(radius.cutoff(crs)>mrs) return true;
1746 crs+=boxx*(-2*xlo+boxx)+boxy*(2*ylo+boxy)+gzs;
1748 } else if(dj<0) {
1749 ylo=(dj+1)*boxy-fy;
1750 crs+=ylo*ylo;
1751 if(dk>0) {
1752 zlo=dk*boxz-fz;
1753 crs+=zlo*zlo;if(radius.cutoff(crs)>mrs) return true;
1754 crs+=bxsq+2*(-boxx*xlo-boxy*ylo+boxz*zlo);
1755 } else if(dk<0) {
1756 zlo=(dk+1)*boxz-fz;
1757 crs+=zlo*zlo;if(radius.cutoff(crs)>mrs) return true;
1758 crs+=bxsq+2*(-boxx*xlo-boxy*ylo-boxz*zlo);
1759 } else {
1760 if(radius.cutoff(crs)>mrs) return true;
1761 crs+=boxx*(-2*xlo+boxx)+boxy*(-2*ylo+boxy)+gzs;
1763 } else {
1764 if(dk>0) {
1765 zlo=dk*boxz-fz;
1766 crs+=zlo*zlo;if(radius.cutoff(crs)>mrs) return true;
1767 crs+=boxz*(2*zlo+boxz);
1768 } else if(dk<0) {
1769 zlo=(dk+1)*boxz-fz;
1770 crs+=zlo*zlo;if(radius.cutoff(crs)>mrs) return true;
1771 crs+=boxz*(-2*zlo+boxz);
1772 } else {
1773 if(radius.cutoff(crs)>mrs) return true;
1774 crs+=gzs;
1776 crs+=gys+boxx*(-2*xlo+boxx);
1778 } else {
1779 if(dj>0) {
1780 ylo=dj*boxy-fy;
1781 crs=ylo*ylo;
1782 if(dk>0) {
1783 zlo=dk*boxz-fz;
1784 crs+=zlo*zlo;if(radius.cutoff(crs)>mrs) return true;
1785 crs+=boxz*(2*zlo+boxz);
1786 } else if(dk<0) {
1787 zlo=(dk+1)*boxz-fz;
1788 crs+=zlo*zlo;if(radius.cutoff(crs)>mrs) return true;
1789 crs+=boxz*(-2*zlo+boxz);
1790 } else {
1791 if(radius.cutoff(crs)>mrs) return true;
1792 crs+=gzs;
1794 crs+=boxy*(2*ylo+boxy);
1795 } else if(dj<0) {
1796 ylo=(dj+1)*boxy-fy;
1797 crs=ylo*ylo;
1798 if(dk>0) {
1799 zlo=dk*boxz-fz;
1800 crs+=zlo*zlo;if(radius.cutoff(crs)>mrs) return true;
1801 crs+=boxz*(2*zlo+boxz);
1802 } else if(dk<0) {
1803 zlo=(dk+1)*boxz-fz;
1804 crs+=zlo*zlo;if(radius.cutoff(crs)>mrs) return true;
1805 crs+=boxz*(-2*zlo+boxz);
1806 } else {
1807 if(radius.cutoff(crs)>mrs) return true;
1808 crs+=gzs;
1810 crs+=boxy*(-2*ylo+boxy);
1811 } else {
1812 if(dk>0) {
1813 zlo=dk*boxz-fz;crs=zlo*zlo;if(radius.cutoff(crs)>mrs) return true;
1814 crs+=boxz*(2*zlo+boxz);
1815 } else if(dk<0) {
1816 zlo=(dk+1)*boxz-fz;crs=zlo*zlo;if(radius.cutoff(crs)>mrs) return true;
1817 crs+=boxz*(-2*zlo+boxz);
1818 } else {
1819 crs=0;
1820 cout << "Can't happen ... happened\n";
1822 crs+=gys;
1824 crs+=gxs;
1826 return false;
1829 #include "worklist.cc"