1 // Voro++, a 3D cell-based Voronoi library
3 // Author : Chris H. Rycroft (LBL / UC Berkeley)
4 // Email : chr@alum.mit.edu
5 // Date : July 1st 2008
8 * \brief Function implementations for the container_base template and related
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
) {
31 for(l
=0;l
<nxyz
;l
++) co
[l
]=0;
33 for(l
=0;l
<nxyz
;l
++) mem
[l
]=memi
;
35 for(l
=0;l
<nxyz
;l
++) id
[l
]=new int[memi
];
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;
42 walls
=new wall
*[current_wall_size
];
43 mrad
=new fpoint
[hgridsq
*seq_length
];
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
;
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
++) {
70 for(q
=e
[0]+1;q
<seq_length
;q
++) {
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
);
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
);
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);
95 compute_minimum(minr
,xlo
,xhi
,ylo
,yhi
,zlo
,zhi
,i
,j
,k
);
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
111 * \param[in] (&xlo,&ylo,&zlo) the lower coordinates of the subregion being
113 * \param[in] (&xhi,&yhi,&zhi) the upper coordinates of the subregion being
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
;
120 if(ti
>0) {temp
=boxx
*ti
-xhi
;radsq
=temp
*temp
;}
121 else if(ti
<0) {temp
=xlo
-boxx
*(1+ti
);radsq
=temp
*temp
;}
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() {
137 for(l
=0;l
<nxyz
;l
++) delete [] p
[l
];
138 for(l
=0;l
<nxyz
;l
++) delete [] id
[l
];
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
) {
154 for(l
=0;l
<nxyz
;l
++) {
155 for(c
=0;c
<co
[l
];c
++) {
157 for(i
=sz
*c
;i
<sz
*(c
+1);i
++) os
<< " " << p
[l
][i
];
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
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
);
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
);
186 os
<< (p
[ijk
][sz
*l
]-ax
)*facx
<< " " << (p
[ijk
][sz
*l
+1]-ay
)*facy
<< " " << (p
[ijk
][sz
*l
+2]-az
)*facz
;
188 os
<< p
[ijk
][sz
*l
] << " " << p
[ijk
][sz
*l
+1] << " " << p
[ijk
][sz
*l
+2];
194 template<class r_option
>
195 void container_base
<r_option
>::skip_lammps_restart(istream
&is
) {
198 for(i
=0;i
<3;i
++) is
.getline(q
,256);
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
) {
209 for(i
=0;i
<3;i
++) is
.getline(q
,256);
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
);
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
) {
230 os
.open(filename
,ofstream::out
|ofstream::trunc
);
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
) {
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] << ">,";
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
) {
263 os
.open(filename
,ofstream::out
|ofstream::trunc
);
264 draw_particles_pov(os
);
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
) {
273 i
=int((x
-ax
)*xsp
);j
=int((y
-ay
)*ysp
);k
=int((z
-az
)*zsp
);
274 if(i
<nx
&&j
<ny
&&k
<nz
) {
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);
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
) {
292 i
=int((x
-ax
)*xsp
);j
=int((y
-ay
)*ysp
);k
=int((z
-az
)*zsp
);
293 if(i
<nx
&&j
<ny
&&k
<nz
) {
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
);
303 /** Increase memory for a particular region. */
304 template<class r_option
>
305 void container_base
<r_option
>::add_particle_memory(int i
) {
308 #if VOROPP_VERBOSE >=3
309 cerr
<< "Particle memory in region " << i
<< " scaled up to " << nmem
<< endl
;
311 if(nmem
>max_particle_memory
) throw fatal_error("Absolute maximum memory allocation exceeded");
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
];
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() {
325 ps
=new int[s_size
*2];
326 #if VOROPP_VERBOSE >=2
327 cerr
<< "List memory scaled up to " << s_size
*2 << endl
;
330 for(i
=s_start
;i
<s_end
;i
++) ps
[j
++]=sl
[i
];
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
];
340 /** Import a list of particles from standard input. */
341 template<class r_option
>
342 void container_base
<r_option
>::import(istream
&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() {
353 /** An overloaded version of the import routine, that reads in particles from
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
) {
359 is
.open(filename
,ifstream::in
);
364 /** Outputs the number of particles within each region. */
365 template<class r_option
>
366 void container_base
<r_option
>::region_count() {
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;
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);
392 os
.open(filename
,ofstream::out
|ofstream::trunc
);
393 s
=l1
.init(xmin
,xmax
,ymin
,ymax
,zmin
,zmax
,px
,py
,pz
);
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);
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);
420 voronoicell_neighbor c
;
422 os
.open(filename
,ofstream::out
|ofstream::trunc
);
423 s
=l1
.init(xmin
,xmax
,ymin
,ymax
,zmin
,zmax
,px
,py
,pz
);
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);
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() {
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
) {
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();
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()
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;
486 s
=l1
.init(cx
,cy
,cz
,r
,px
,py
,pz
);
488 for(q
=0;q
<co
[s
];q
++) {
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
);
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()
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;
513 s
=l1
.init(xmin
,xmax
,ymin
,ymax
,zmin
,zmax
,px
,py
,pz
);
515 for(q
=0;q
<co
[s
];q
++) {
519 if(x
>xmin
&&x
<xmax
&&y
>ymin
&&y
<ymax
&&z
>zmin
&&z
<zmax
) {
520 pvol
+=radius
.volume(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() {
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();
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
) {
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";
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
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
) {
572 os
.open(filename
,ofstream::out
|ofstream::trunc
);
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
) {
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();
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
) {
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() {
613 /** An overloaded version of print_all(), which outputs the result to a particular
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
) {
620 os
.open(filename
,ofstream::out
|ofstream::trunc
);
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
;
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
;
642 /** An overloaded version of print_all_neighbor(), which outputs the result to a
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
;
649 os
.open(filename
,ofstream::out
|ofstream::trunc
);
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;
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
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
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;
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
706 * \param[in] ijk the index of the block that the test particle is in, set to
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
;
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.
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
);
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);
743 /** A overloaded version of compute_cell_sphere(), that sets up the x, y, and z
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
748 * \param[in] ijk the index of the block that the test particle is in, set to
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
764 * \param[in] ijk the index of the block that the test particle is in, set to
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
793 * \param[in] ijk the index of the block that the test particle is in, set to
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;
811 // Initialize the Voronoi cell to fill the entire container
812 if (!initialize_voronoicell(c
,x
,y
,z
)) return false;
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
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;
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;
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.
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
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.
858 m1
=127+(3<<21);si
=fgrid
-1-si
;m2
=1+(1<<21);
859 } else {m1
=m2
=0;gxs
=boxx
-fx
;}
862 m1
|=(127<<7)+(3<<24);sj
=fgrid
-1-sj
;m2
|=(1<<7)+(1<<24);
866 m1
|=(127<<14)+(3<<27);sk
=fgrid
-1-sk
;m2
|=(1<<14)+(1<<27);
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
886 // At the intervals specified by count_list, we recompute the
887 // maximum radius squared
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;
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.
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.
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;
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
);
948 if (!c
.nplane(x1
,y1
,z1
,rs
,id
[dijk
][l
])) return false;
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.
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
970 for(l
=0;l
<hxyz
;l
++) mask
[l
]=0;
974 // Reset the block by block counters
977 while(g
<seq_length
-1) {
979 // At the intervals specified by count_list, we recompute the
980 // maximum radius squared
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;
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.
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
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
);
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.
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;
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
);
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.
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
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
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
1096 if(corner_test(c
,xlo
,ylo
,zlo
,xhi
,yhi
,zhi
)) continue;
1098 if(corner_test(c
,xlo
,ylo
,zhi
,xhi
,yhi
,zlo
)) continue;
1100 if(edge_z_test(c
,xlo
,ylo
,zlo
,xhi
,yhi
,zhi
)) continue;
1104 if(corner_test(c
,xlo
,yhi
,zlo
,xhi
,ylo
,zhi
)) continue;
1106 if(corner_test(c
,xlo
,yhi
,zhi
,xhi
,ylo
,zlo
)) continue;
1108 if(edge_z_test(c
,xlo
,yhi
,zlo
,xhi
,ylo
,zhi
)) continue;
1112 if(edge_y_test(c
,xlo
,ylo
,zlo
,xhi
,yhi
,zhi
)) continue;
1114 if(edge_y_test(c
,xlo
,ylo
,zhi
,xhi
,yhi
,zlo
)) continue;
1116 if(face_x_test(c
,xlo
,ylo
,zlo
,yhi
,zhi
)) continue;
1122 if(corner_test(c
,xhi
,ylo
,zlo
,xlo
,yhi
,zhi
)) continue;
1124 if(corner_test(c
,xhi
,ylo
,zhi
,xlo
,yhi
,zlo
)) continue;
1126 if(edge_z_test(c
,xhi
,ylo
,zlo
,xlo
,yhi
,zhi
)) continue;
1130 if(corner_test(c
,xhi
,yhi
,zlo
,xlo
,ylo
,zhi
)) continue;
1132 if(corner_test(c
,xhi
,yhi
,zhi
,xlo
,ylo
,zlo
)) continue;
1134 if(edge_z_test(c
,xhi
,yhi
,zlo
,xlo
,ylo
,zhi
)) continue;
1138 if(edge_y_test(c
,xhi
,ylo
,zlo
,xlo
,yhi
,zhi
)) continue;
1140 if(edge_y_test(c
,xhi
,ylo
,zhi
,xlo
,yhi
,zlo
)) continue;
1142 if(face_x_test(c
,xhi
,ylo
,zlo
,yhi
,zhi
)) continue;
1148 if(edge_x_test(c
,xlo
,ylo
,zlo
,xhi
,yhi
,zhi
)) continue;
1150 if(edge_x_test(c
,xlo
,ylo
,zhi
,xhi
,yhi
,zlo
)) continue;
1152 if(face_y_test(c
,xlo
,ylo
,zlo
,xhi
,zhi
)) continue;
1156 if(edge_x_test(c
,xlo
,yhi
,zlo
,xhi
,ylo
,zhi
)) continue;
1158 if(edge_x_test(c
,xlo
,yhi
,zhi
,xhi
,ylo
,zlo
)) continue;
1160 if(face_y_test(c
,xlo
,yhi
,zlo
,xhi
,zhi
)) continue;
1164 if(face_z_test(c
,xlo
,ylo
,zlo
,xhi
,yhi
)) continue;
1166 if(face_z_test(c
,xlo
,ylo
,zhi
,xhi
,yhi
)) continue;
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;}
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
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;
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
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
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;
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
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
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;
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
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
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;
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;
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;
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;
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
);
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
);
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
);
1380 if(ak
<0) {ak
=0;if(bk
<0) bk
=0;}
1381 if(bk
>=nz
) {bk
=nz
-1;if(ak
>=nz
) ak
=nz
-1;}
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
;
1390 s
=aip
+nx
*(ajp
+ny
*akp
);
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)
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
);
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
);
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
);
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
;
1423 return reset(px
,py
,pz
);
1426 inline int voropp_loop::reset(fpoint
&px
,fpoint
&py
,fpoint
&pz
) {
1428 ip
=aip
;jp
=ajp
;kp
=akp
;
1429 px
=apx
;py
=apy
;pz
=apz
;
1430 s
=aip
+nx
*(ajp
+ny
*akp
);
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
) {
1439 if(ip
<nx
-1) {ip
++;s
++;} else {ip
=0;s
+=1-nx
;px
+=sx
;}
1442 i
=ai
;ip
=aip
;px
=apx
;j
++;
1443 if(jp
<ny
-1) {jp
++;s
+=inc1
;} else {jp
=0;s
+=inc1
-nxy
;py
+=sy
;}
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
;}
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");
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
) {
1494 if(r
>max_radius
) max_radius
=r
;
1497 /** Clears the stored maximum radius. */
1498 inline void radius_poly::clear_max() {
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
;
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
;}
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
;
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
;}
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
) {
1535 is
>> 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
;
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
));
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
) {
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
) {
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
) {
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
) {
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
1624 inline fpoint
radius_mono::volume(int ijk
,int s
) {
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];
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
) {
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
) {
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
;
1690 crs
+=zlo
*zlo
;if(radius
.cutoff(crs
)>mrs
) return true;
1691 crs
+=bxsq
+2*(boxx
*xlo
+boxy
*ylo
+boxz
*zlo
);
1694 crs
+=zlo
*zlo
;if(radius
.cutoff(crs
)>mrs
) return true;
1695 crs
+=bxsq
+2*(boxx
*xlo
+boxy
*ylo
-boxz
*zlo
);
1697 if(radius
.cutoff(crs
)>mrs
) return true;
1698 crs
+=boxx
*(2*xlo
+boxx
)+boxy
*(2*ylo
+boxy
)+gzs
;
1705 crs
+=zlo
*zlo
;if(radius
.cutoff(crs
)>mrs
) return true;
1706 crs
+=bxsq
+2*(boxx
*xlo
-boxy
*ylo
+boxz
*zlo
);
1709 crs
+=zlo
*zlo
;if(radius
.cutoff(crs
)>mrs
) return true;
1710 crs
+=bxsq
+2*(boxx
*xlo
-boxy
*ylo
-boxz
*zlo
);
1712 if(radius
.cutoff(crs
)>mrs
) return true;
1713 crs
+=boxx
*(2*xlo
+boxx
)+boxy
*(-2*ylo
+boxy
)+gzs
;
1718 crs
+=zlo
*zlo
;if(radius
.cutoff(crs
)>mrs
) return true;
1719 crs
+=boxz
*(2*zlo
+boxz
);
1722 crs
+=zlo
*zlo
;if(radius
.cutoff(crs
)>mrs
) return true;
1723 crs
+=boxz
*(-2*zlo
+boxz
);
1725 if(radius
.cutoff(crs
)>mrs
) return true;
1728 crs
+=gys
+boxx
*(2*xlo
+boxx
);
1738 crs
+=zlo
*zlo
;if(radius
.cutoff(crs
)>mrs
) return true;
1739 crs
+=bxsq
+2*(-boxx
*xlo
+boxy
*ylo
+boxz
*zlo
);
1742 crs
+=zlo
*zlo
;if(radius
.cutoff(crs
)>mrs
) return true;
1743 crs
+=bxsq
+2*(-boxx
*xlo
+boxy
*ylo
-boxz
*zlo
);
1745 if(radius
.cutoff(crs
)>mrs
) return true;
1746 crs
+=boxx
*(-2*xlo
+boxx
)+boxy
*(2*ylo
+boxy
)+gzs
;
1753 crs
+=zlo
*zlo
;if(radius
.cutoff(crs
)>mrs
) return true;
1754 crs
+=bxsq
+2*(-boxx
*xlo
-boxy
*ylo
+boxz
*zlo
);
1757 crs
+=zlo
*zlo
;if(radius
.cutoff(crs
)>mrs
) return true;
1758 crs
+=bxsq
+2*(-boxx
*xlo
-boxy
*ylo
-boxz
*zlo
);
1760 if(radius
.cutoff(crs
)>mrs
) return true;
1761 crs
+=boxx
*(-2*xlo
+boxx
)+boxy
*(-2*ylo
+boxy
)+gzs
;
1766 crs
+=zlo
*zlo
;if(radius
.cutoff(crs
)>mrs
) return true;
1767 crs
+=boxz
*(2*zlo
+boxz
);
1770 crs
+=zlo
*zlo
;if(radius
.cutoff(crs
)>mrs
) return true;
1771 crs
+=boxz
*(-2*zlo
+boxz
);
1773 if(radius
.cutoff(crs
)>mrs
) return true;
1776 crs
+=gys
+boxx
*(-2*xlo
+boxx
);
1784 crs
+=zlo
*zlo
;if(radius
.cutoff(crs
)>mrs
) return true;
1785 crs
+=boxz
*(2*zlo
+boxz
);
1788 crs
+=zlo
*zlo
;if(radius
.cutoff(crs
)>mrs
) return true;
1789 crs
+=boxz
*(-2*zlo
+boxz
);
1791 if(radius
.cutoff(crs
)>mrs
) return true;
1794 crs
+=boxy
*(2*ylo
+boxy
);
1800 crs
+=zlo
*zlo
;if(radius
.cutoff(crs
)>mrs
) return true;
1801 crs
+=boxz
*(2*zlo
+boxz
);
1804 crs
+=zlo
*zlo
;if(radius
.cutoff(crs
)>mrs
) return true;
1805 crs
+=boxz
*(-2*zlo
+boxz
);
1807 if(radius
.cutoff(crs
)>mrs
) return true;
1810 crs
+=boxy
*(-2*ylo
+boxy
);
1813 zlo
=dk
*boxz
-fz
;crs
=zlo
*zlo
;if(radius
.cutoff(crs
)>mrs
) return true;
1814 crs
+=boxz
*(2*zlo
+boxz
);
1816 zlo
=(dk
+1)*boxz
-fz
;crs
=zlo
*zlo
;if(radius
.cutoff(crs
)>mrs
) return true;
1817 crs
+=boxz
*(-2*zlo
+boxz
);
1820 cout
<< "Can't happen ... happened\n";
1829 #include "worklist.cc"