1 // Voro++, a 3D cell-based Voronoi library
3 // Author : Chris H. Rycroft (LBL / UC Berkeley)
4 // Email : chr@alum.mit.edu
5 // Date : August 30th 2011
7 /** \file container_prd.cc
8 * \brief Function implementations for the container_periodic_base and
11 #include "container_prd.hh"
15 /** The class constructor sets up the geometry of container, initializing the
16 * minimum and maximum coordinates in each direction, and setting whether each
17 * direction is periodic or not. It divides the container into a rectangular
18 * grid of blocks, and allocates memory for each of these for storing particle
20 * \param[in] (bx_) The x coordinate of the first unit vector.
21 * \param[in] (bxy_,by_) The x and y coordinates of the second unit vector.
22 * \param[in] (bxz_,byz_,bz_) The x, y, and z coordinates of the third unit
24 * \param[in] (nx_,ny_,nz_) the number of grid blocks in each of the three
25 * coordinate directions.
26 * \param[in] init_mem_ the initial memory allocation for each block.
27 * \param[in] ps_ the number of floating point entries to store for each
29 container_periodic_base::container_periodic_base(double bx_
,double bxy_
,double by_
,
30 double bxz_
,double byz_
,double bz_
,int nx_
,int ny_
,int nz_
,int init_mem_
,int ps_
)
31 : unitcell(bx_
,bxy_
,by_
,bxz_
,byz_
,bz_
),
32 voro_base(nx_
,ny_
,nz_
,bx_
/nx_
,by_
/ny_
,bz_
/nz_
), max_len_sq(unit_voro
.max_radius_squared()),
33 ey(int(max_uv_y
*ysp
+1)), ez(int(max_uv_z
*zsp
+1)), wy(ny
+ey
), wz(nz
+ez
),
34 oy(ny
+2*ey
), oz(nz
+2*ez
), oxyz(nx
*oy
*oz
), id(new int*[oxyz
]), p(new double*[oxyz
]),
35 co(new int[oxyz
]), mem(new int[oxyz
]), img(new char[oxyz
]), init_mem(init_mem_
), ps(ps_
) {
38 // Clear the global arrays
39 int *pp
=co
;while(pp
<co
+oxyz
) *(pp
++)=0;
40 pp
=mem
;while(pp
<mem
+oxyz
) *(pp
++)=0;
41 char *cp
=img
;while(cp
<img
+oxyz
) *(cp
++)=0;
43 // Set up memory for the blocks in the primary domain
44 for(k
=ez
;k
<wz
;k
++) for(j
=ey
;j
<wy
;j
++) for(i
=0;i
<nx
;i
++) {
47 id
[l
]=new int[init_mem
];
48 p
[l
]=new double[ps
*init_mem
];
52 /** The container destructor frees the dynamically allocated memory. */
53 container_periodic_base::~container_periodic_base() {
54 for(int l
=oxyz
-1;l
>=0;l
--) if(mem
[l
]>0) {
65 /** The class constructor sets up the geometry of container.
66 * \param[in] (bx_) The x coordinate of the first unit vector.
67 * \param[in] (bxy_,by_) The x and y coordinates of the second unit vector.
68 * \param[in] (bxz_,byz_,bz_) The x, y, and z coordinates of the third unit
70 * \param[in] (nx_,ny_,nz_) the number of grid blocks in each of the three
71 * coordinate directions.
72 * \param[in] init_mem_ the initial memory allocation for each block. */
73 container_periodic::container_periodic(double bx_
,double bxy_
,double by_
,double bxz_
,double byz_
,double bz_
,
74 int nx_
,int ny_
,int nz_
,int init_mem_
)
75 : container_periodic_base(bx_
,bxy_
,by_
,bxz_
,byz_
,bz_
,nx_
,ny_
,nz_
,init_mem_
,3),
76 vc(*this,2*nx_
+1,2*ey
+1,2*ez
+1) {}
78 /** The class constructor sets up the geometry of container.
79 * \param[in] (bx_) The x coordinate of the first unit vector.
80 * \param[in] (bxy_,by_) The x and y coordinates of the second unit vector.
81 * \param[in] (bxz_,byz_,bz_) The x, y, and z coordinates of the third unit
83 * \param[in] (nx_,ny_,nz_) the number of grid blocks in each of the three
84 * coordinate directions.
85 * \param[in] init_mem_ the initial memory allocation for each block. */
86 container_periodic_poly::container_periodic_poly(double bx_
,double bxy_
,double by_
,double bxz_
,double byz_
,double bz_
,
87 int nx_
,int ny_
,int nz_
,int init_mem_
)
88 : container_periodic_base(bx_
,bxy_
,by_
,bxz_
,byz_
,bz_
,nx_
,ny_
,nz_
,init_mem_
,4),
89 vc(*this,2*nx_
+1,2*ey
+1,2*ez
+1) {ppr
=p
;}
91 /** Put a particle into the correct region of the container.
92 * \param[in] n the numerical ID of the inserted particle.
93 * \param[in] (x,y,z) the position vector of the inserted particle. */
94 void container_periodic::put(int n
,double x
,double y
,double z
) {
96 put_locate_block(ijk
,x
,y
,z
);
97 for(int l
=0;l
<co
[ijk
];l
++) check_duplicate(n
,x
,y
,z
,id
[ijk
][l
],p
[ijk
]+3*l
);
99 double *pp
=p
[ijk
]+3*co
[ijk
]++;
100 *(pp
++)=x
;*(pp
++)=y
;*pp
=z
;
103 /** Put a particle into the correct region of the container.
104 * \param[in] n the numerical ID of the inserted particle.
105 * \param[in] (x,y,z) the position vector of the inserted particle.
106 * \param[in] r the radius of the particle. */
107 void container_periodic_poly::put(int n
,double x
,double y
,double z
,double r
) {
109 put_locate_block(ijk
,x
,y
,z
);
110 for(int l
=0;l
<co
[ijk
];l
++) check_duplicate(n
,x
,y
,z
,id
[ijk
][l
],p
[ijk
]+4*l
);
112 double *pp
=p
[ijk
]+4*co
[ijk
]++;
113 *(pp
++)=x
;*(pp
++)=y
;*(pp
++)=z
;*pp
=r
;
114 if(max_radius
<r
) max_radius
=r
;
117 /** Put a particle into the correct region of the container.
118 * \param[in] n the numerical ID of the inserted particle.
119 * \param[in] (x,y,z) the position vector of the inserted particle.
120 * \param[out] (ai,aj,ak) the periodic image displacement that the particle is
121 * in, with (0,0,0) corresponding to the primary domain.
123 void container_periodic::put(int n
,double x
,double y
,double z
,int &ai
,int &aj
,int &ak
) {
125 put_locate_block(ijk
,x
,y
,z
,ai
,aj
,ak
);
126 for(int l
=0;l
<co
[ijk
];l
++) check_duplicate(n
,x
,y
,z
,id
[ijk
][l
],p
[ijk
]+3*l
);
128 double *pp
=p
[ijk
]+3*co
[ijk
]++;
129 *(pp
++)=x
;*(pp
++)=y
;*pp
=z
;
132 /** Put a particle into the correct region of the container.
133 * \param[in] n the numerical ID of the inserted particle.
134 * \param[in] (x,y,z) the position vector of the inserted particle.
135 * \param[in] r the radius of the particle.
136 * \param[out] (ai,aj,ak) the periodic image displacement that the particle is
137 * in, with (0,0,0) corresponding to the primary domain.
139 void container_periodic_poly::put(int n
,double x
,double y
,double z
,double r
,int &ai
,int &aj
,int &ak
) {
141 put_locate_block(ijk
,x
,y
,z
,ai
,aj
,ak
);
142 for(int l
=0;l
<co
[ijk
];l
++) check_duplicate(n
,x
,y
,z
,id
[ijk
][l
],p
[ijk
]+4*l
);
145 double *pp
=p
[ijk
]+4*co
[ijk
]++;
146 *(pp
++)=x
;*(pp
++)=y
;*(pp
++)=z
;*pp
=r
;
147 if(max_radius
<r
) max_radius
=r
;
150 /** Put a particle into the correct region of the container, also recording
151 * into which region it was stored.
152 * \param[in] vo the ordering class in which to record the region.
153 * \param[in] n the numerical ID of the inserted particle.
154 * \param[in] (x,y,z) the position vector of the inserted particle. */
155 void container_periodic::put(particle_order
&vo
,int n
,double x
,double y
,double z
) {
157 put_locate_block(ijk
,x
,y
,z
);
160 double *pp
=p
[ijk
]+3*co
[ijk
]++;
161 *(pp
++)=x
;*(pp
++)=y
;*pp
=z
;
164 /** Put a particle into the correct region of the container, also recording
165 * into which region it was stored.
166 * \param[in] vo the ordering class in which to record the region.
167 * \param[in] n the numerical ID of the inserted particle.
168 * \param[in] (x,y,z) the position vector of the inserted particle.
169 * \param[in] r the radius of the particle. */
170 void container_periodic_poly::put(particle_order
&vo
,int n
,double x
,double y
,double z
,double r
) {
172 put_locate_block(ijk
,x
,y
,z
);
175 double *pp
=p
[ijk
]+4*co
[ijk
]++;
176 *(pp
++)=x
;*(pp
++)=y
;*(pp
++)=z
;*pp
=r
;
177 if(max_radius
<r
) max_radius
=r
;
180 /** Takes a particle position vector and computes the region index into which
181 * it should be stored. If the container is periodic, then the routine also
182 * maps the particle position to ensure it is in the primary domain. If the
183 * container is not periodic, the routine bails out.
184 * \param[out] ijk the region index.
185 * \param[in,out] (x,y,z) the particle position, remapped into the primary
186 * domain if necessary.
187 * \return True if the particle can be successfully placed into the container,
188 * false otherwise. */
189 void container_periodic_base::put_locate_block(int &ijk
,double &x
,double &y
,double &z
) {
191 // Remap particle in the z direction if necessary
192 int k
=step_int(z
*zsp
);
194 int ak
=step_div(k
,nz
);
195 z
-=ak
*bz
;y
-=ak
*byz
;x
-=ak
*bxz
;k
-=ak
*nz
;
198 // Remap particle in the y direction if necessary
199 int j
=step_int(y
*ysp
);
201 int aj
=step_div(j
,ny
);
202 y
-=aj
*by
;x
-=aj
*bxy
;j
-=aj
*ny
;
205 // Remap particle in the x direction if necessary
208 int ai
=step_div(ijk
,nx
);
212 // Compute the block index and check memory allocation
215 if(co
[ijk
]==mem
[ijk
]) add_particle_memory(ijk
);
218 /** Takes a particle position vector and computes the region index into which
219 * it should be stored. If the container is periodic, then the routine also
220 * maps the particle position to ensure it is in the primary domain. If the
221 * container is not periodic, the routine bails out.
222 * \param[out] ijk the region index.
223 * \param[in,out] (x,y,z) the particle position, remapped into the primary
224 * domain if necessary.
225 * \param[out] (ai,aj,ak) the periodic image displacement that the particle is
226 * in, with (0,0,0) corresponding to the primary domain.
227 * \return True if the particle can be successfully placed into the container,
228 * false otherwise. */
229 void container_periodic_base::put_locate_block(int &ijk
,double &x
,double &y
,double &z
,int &ai
,int &aj
,int &ak
) {
231 // Remap particle in the z direction if necessary
232 int k
=step_int(z
*zsp
);
235 z
-=ak
*bz
;y
-=ak
*byz
;x
-=ak
*bxz
;k
-=ak
*nz
;
238 // Remap particle in the y direction if necessary
239 int j
=step_int(y
*ysp
);
242 y
-=aj
*by
;x
-=aj
*bxy
;j
-=aj
*ny
;
245 // Remap particle in the x direction if necessary
252 // Compute the block index and check memory allocation
255 if(co
[ijk
]==mem
[ijk
]) add_particle_memory(ijk
);
258 /** Takes a position vector and remaps it into the primary domain.
259 * \param[out] (ai,aj,ak) the periodic image displacement that the vector is in,
260 * with (0,0,0) corresponding to the primary domain.
261 * \param[out] (ci,cj,ck) the index of the block that the position vector is
262 * within, once it has been remapped.
263 * \param[in,out] (x,y,z) the position vector to consider, which is remapped
264 * into the primary domain during the routine.
265 * \param[out] ijk the block index that the vector is within. */
266 inline void container_periodic_base::remap(int &ai
,int &aj
,int &ak
,int &ci
,int &cj
,int &ck
,double &x
,double &y
,double &z
,int &ijk
) {
268 // Remap particle in the z direction if necessary
272 z
-=ak
*bz
;y
-=ak
*byz
;x
-=ak
*bxz
;ck
-=ak
*nz
;
275 // Remap particle in the y direction if necessary
279 y
-=aj
*by
;x
-=aj
*bxy
;cj
-=aj
*ny
;
282 // Remap particle in the x direction if necessary
290 ijk
=ci
+nx
*(cj
+oy
*ck
);
293 /** Takes a vector and finds the particle whose Voronoi cell contains that
294 * vector. This is equivalent to finding the particle which is nearest to the
296 * \param[in] (x,y,z) the vector to test.
297 * \param[out] (rx,ry,rz) the position of the particle whose Voronoi cell
298 * contains the vector. This may point to a particle in
299 * a periodic image of the primary domain.
300 * \param[out] pid the ID of the particle.
301 * \return True if a particle was found. If the container has no particles,
302 * then the search will not find a Voronoi cell and false is returned. */
303 bool container_periodic::find_voronoi_cell(double x
,double y
,double z
,double &rx
,double &ry
,double &rz
,int &pid
) {
304 int ai
,aj
,ak
,ci
,cj
,ck
,ijk
;
308 // Remap the vector into the primary domain and then search for the
309 // Voronoi cell that it is within
310 remap(ai
,aj
,ak
,ci
,cj
,ck
,x
,y
,z
,ijk
);
311 vc
.find_voronoi_cell(x
,y
,z
,ci
,cj
,ck
,ijk
,w
,mrs
);
315 // Assemble the position vector of the particle to be returned,
316 // applying a periodic remapping if necessary
317 ci
+=w
.di
;if(ci
<0||ci
>=nx
) ai
+=step_div(ci
,nx
);
318 rx
=p
[w
.ijk
][3*w
.l
]+ak
*bxz
+aj
*bxy
+ai
*bx
;
319 ry
=p
[w
.ijk
][3*w
.l
+1]+ak
*byz
+aj
*by
;
320 rz
=p
[w
.ijk
][3*w
.l
+2]+ak
*bz
;
327 /** Takes a vector and finds the particle whose Voronoi cell contains that
328 * vector. Additional wall classes are not considered by this routine.
329 * \param[in] (x,y,z) the vector to test.
330 * \param[out] (rx,ry,rz) the position of the particle whose Voronoi cell
331 * contains the vector. If the container is periodic,
332 * this may point to a particle in a periodic image of
333 * the primary domain.
334 * \param[out] pid the ID of the particle.
335 * \return True if a particle was found. If the container has no particles,
336 * then the search will not find a Voronoi cell and false is returned. */
337 bool container_periodic_poly::find_voronoi_cell(double x
,double y
,double z
,double &rx
,double &ry
,double &rz
,int &pid
) {
338 int ai
,aj
,ak
,ci
,cj
,ck
,ijk
;
342 // Remap the vector into the primary domain and then search for the
343 // Voronoi cell that it is within
344 remap(ai
,aj
,ak
,ci
,cj
,ck
,x
,y
,z
,ijk
);
345 vc
.find_voronoi_cell(x
,y
,z
,ci
,cj
,ck
,ijk
,w
,mrs
);
349 // Assemble the position vector of the particle to be returned,
350 // applying a periodic remapping if necessary
351 ci
+=w
.di
;if(ci
<0||ci
>=nx
) ai
+=step_div(ci
,nx
);
352 rx
=p
[w
.ijk
][4*w
.l
]+ak
*bxz
+aj
*bxy
+ai
*bx
;
353 ry
=p
[w
.ijk
][4*w
.l
+1]+ak
*byz
+aj
*by
;
354 rz
=p
[w
.ijk
][4*w
.l
+2]+ak
*bz
;
361 /** Increase memory for a particular region.
362 * \param[in] i the index of the region to reallocate. */
363 void container_periodic_base::add_particle_memory(int i
) {
365 // Handle the case when no memory has been allocated for this block
368 id
[i
]=new int[init_mem
];
369 p
[i
]=new double[ps
*init_mem
];
373 // Otherwise, double the memory allocation for this block. Carry out a
374 // check on the memory allocation size, and print a status message if
376 int l
,nmem(mem
[i
]<<1);
377 if(nmem
>max_particle_memory
)
378 voro_fatal_error("Absolute maximum memory allocation exceeded",VOROPP_MEMORY_ERROR
);
379 #if VOROPP_VERBOSE >=3
380 fprintf(stderr
,"Particle memory in region %d scaled up to %d\n",i
,nmem
);
383 // Allocate new memory and copy in the contents of the old arrays
384 int *idp
=new int[nmem
];
385 for(l
=0;l
<co
[i
];l
++) idp
[l
]=id
[i
][l
];
386 double *pp
=new double[ps
*nmem
];
387 for(l
=0;l
<ps
*co
[i
];l
++) pp
[l
]=p
[i
][l
];
389 // Update pointers and delete old arrays
391 delete [] id
[i
];id
[i
]=idp
;
392 delete [] p
[i
];p
[i
]=pp
;
395 /** Import a list of particles from an open file stream into the container.
396 * Entries of four numbers (Particle ID, x position, y position, z position)
397 * are searched for. If the file cannot be successfully read, then the routine
398 * causes a fatal error.
399 * \param[in] fp the file handle to read from. */
400 void container_periodic::import(FILE *fp
) {
403 while((j
=fscanf(fp
,"%d %lg %lg %lg",&i
,&x
,&y
,&z
))==4) put(i
,x
,y
,z
);
404 if(j
!=EOF
) voro_fatal_error("File import error",VOROPP_FILE_ERROR
);
407 /** Import a list of particles from an open file stream, also storing the order
408 * of that the particles are read. Entries of four numbers (Particle ID, x
409 * position, y position, z position) are searched for. If the file cannot be
410 * successfully read, then the routine causes a fatal error.
411 * \param[in,out] vo a reference to an ordering class to use.
412 * \param[in] fp the file handle to read from. */
413 void container_periodic::import(particle_order
&vo
,FILE *fp
) {
416 while((j
=fscanf(fp
,"%d %lg %lg %lg",&i
,&x
,&y
,&z
))==4) put(vo
,i
,x
,y
,z
);
417 if(j
!=EOF
) voro_fatal_error("File import error",VOROPP_FILE_ERROR
);
420 /** Import a list of particles from an open file stream into the container.
421 * Entries of five numbers (Particle ID, x position, y position, z position,
422 * radius) are searched for. If the file cannot be successfully read, then the
423 * routine causes a fatal error.
424 * \param[in] fp the file handle to read from. */
425 void container_periodic_poly::import(FILE *fp
) {
428 while((j
=fscanf(fp
,"%d %lg %lg %lg %lg",&i
,&x
,&y
,&z
,&r
))==5) put(i
,x
,y
,z
,r
);
429 if(j
!=EOF
) voro_fatal_error("File import error",VOROPP_FILE_ERROR
);
432 /** Import a list of particles from an open file stream, also storing the order
433 * of that the particles are read. Entries of four numbers (Particle ID, x
434 * position, y position, z position, radius) are searched for. If the file
435 * cannot be successfully read, then the routine causes a fatal error.
436 * \param[in,out] vo a reference to an ordering class to use.
437 * \param[in] fp the file handle to read from. */
438 void container_periodic_poly::import(particle_order
&vo
,FILE *fp
) {
441 while((j
=fscanf(fp
,"%d %lg %lg %lg %lg",&i
,&x
,&y
,&z
,&r
))==5) put(vo
,i
,x
,y
,z
,r
);
442 if(j
!=EOF
) voro_fatal_error("File import error",VOROPP_FILE_ERROR
);
445 /** Outputs the a list of all the container regions along with the number of
446 * particles stored within each. */
447 void container_periodic_base::region_count() {
449 for(k
=0;k
<nz
;k
++) for(j
=0;j
<ny
;j
++) for(i
=0;i
<nx
;i
++)
450 printf("Region (%d,%d,%d): %d particles\n",i
,j
,k
,*(cop
++));
453 /** Clears a container of particles. */
454 void container_periodic::clear() {
455 for(int *cop
=co
;cop
<co
+nxyz
;cop
++) *cop
=0;
458 /** Clears a container of particles, also clearing resetting the maximum radius
460 void container_periodic_poly::clear() {
461 for(int *cop
=co
;cop
<co
+nxyz
;cop
++) *cop
=0;
465 /** Computes all the Voronoi cells and saves customized information about them.
466 * \param[in] format the custom output string to use.
467 * \param[in] fp a file handle to write to. */
468 void container_periodic::print_custom(const char *format
,FILE *fp
) {
469 c_loop_all_periodic
vl(*this);
470 print_custom(vl
,format
,fp
);
473 /** Computes all the Voronoi cells and saves customized
474 * information about them.
475 * \param[in] format the custom output string to use.
476 * \param[in] fp a file handle to write to. */
477 void container_periodic_poly::print_custom(const char *format
,FILE *fp
) {
478 c_loop_all_periodic
vl(*this);
479 print_custom(vl
,format
,fp
);
482 /** Computes all the Voronoi cells and saves customized information about them.
483 * \param[in] format the custom output string to use.
484 * \param[in] filename the name of the file to write to. */
485 void container_periodic::print_custom(const char *format
,const char *filename
) {
486 FILE *fp
=safe_fopen(filename
,"w");
487 print_custom(format
,fp
);
491 /** Computes all the Voronoi cells and saves customized
492 * information about them
493 * \param[in] format the custom output string to use.
494 * \param[in] filename the name of the file to write to. */
495 void container_periodic_poly::print_custom(const char *format
,const char *filename
) {
496 FILE *fp
=safe_fopen(filename
,"w");
497 print_custom(format
,fp
);
501 /** Computes all of the Voronoi cells in the container, but does nothing
502 * with the output. It is useful for measuring the pure computation time
503 * of the Voronoi algorithm, without any additional calculations such as
504 * volume evaluation or cell output. */
505 void container_periodic::compute_all_cells() {
506 voronoicell
c(*this);
507 c_loop_all_periodic
vl(*this);
508 if(vl
.start()) do compute_cell(c
,vl
);
512 /** Computes all of the Voronoi cells in the container, but does nothing
513 * with the output. It is useful for measuring the pure computation time
514 * of the Voronoi algorithm, without any additional calculations such as
515 * volume evaluation or cell output. */
516 void container_periodic_poly::compute_all_cells() {
517 voronoicell
c(*this);
518 c_loop_all_periodic
vl(*this);
519 if(vl
.start()) do compute_cell(c
,vl
);while(vl
.inc());
522 /** Calculates all of the Voronoi cells and sums their volumes. In most cases
523 * without walls, the sum of the Voronoi cell volumes should equal the volume
524 * of the container to numerical precision.
525 * \return The sum of all of the computed Voronoi volumes. */
526 double container_periodic::sum_cell_volumes() {
527 voronoicell
c(*this);
529 c_loop_all_periodic
vl(*this);
530 if(vl
.start()) do if(compute_cell(c
,vl
)) vol
+=c
.volume();while(vl
.inc());
534 /** Calculates all of the Voronoi cells and sums their volumes. In most cases
535 * without walls, the sum of the Voronoi cell volumes should equal the volume
536 * of the container to numerical precision.
537 * \return The sum of all of the computed Voronoi volumes. */
538 double container_periodic_poly::sum_cell_volumes() {
539 voronoicell
c(*this);
541 c_loop_all_periodic
vl(*this);
542 if(vl
.start()) do if(compute_cell(c
,vl
)) vol
+=c
.volume();while(vl
.inc());
546 /** This routine creates all periodic images of the particles. It is meant for
547 * diagnostic purposes only, since usually periodic images are dynamically
548 * created in when they are referenced. */
549 void container_periodic_base::create_all_images() {
551 for(k
=0;k
<oz
;k
++) for(j
=0;j
<oy
;j
++) for(i
=0;i
<nx
;i
++) create_periodic_image(i
,j
,k
);
554 /** Checks that the particles within each block lie within that block's bounds.
555 * This is useful for diagnosing problems with periodic image computation. */
556 void container_periodic_base::check_compartmentalized() {
558 double mix
,miy
,miz
,max
,may
,maz
,*pp
;
559 for(k
=l
=0;k
<oz
;k
++) for(j
=0;j
<oy
;j
++) for(i
=0;i
<nx
;i
++,l
++) if(mem
[l
]>0) {
561 // Compute the block's bounds, adding in a small tolerance
562 mix
=i
*boxx
-tolerance
;max
=mix
+boxx
+tolerance
;
563 miy
=(j
-ey
)*boxy
-tolerance
;may
=miy
+boxy
+tolerance
;
564 miz
=(k
-ez
)*boxz
-tolerance
;maz
=miz
+boxz
+tolerance
;
566 // Print entries for any particles that lie outside the block's
568 for(pp
=p
[l
],c
=0;c
<co
[l
];c
++,pp
+=ps
) if(*pp
<mix
||*pp
>max
||pp
[1]<miy
||pp
[1]>may
||pp
[2]<miz
||pp
[2]>maz
)
569 printf("%d %d %d %d %f %f %f %f %f %f %f %f %f\n",
570 id
[l
][c
],i
,j
,k
,*pp
,pp
[1],pp
[2],mix
,max
,miy
,may
,miz
,maz
);
574 /** Creates particles within an image block that is aligned with the primary
575 * domain in the z axis. In this case, the image block may be comprised of
576 * particles from two primary blocks. The routine considers these two primary
577 * blocks, and adds the needed particles to the image. The remaining particles
578 * from the primary blocks are also filled into the neighboring images.
579 * \param[in] (di,dj,dk) the index of the block to consider. The z index must
580 * satisfy ez<=dk<wz. */
581 void container_periodic_base::create_side_image(int di
,int dj
,int dk
) {
582 int l
,dijk
=di
+nx
*(dj
+oy
*dk
),odijk
,ima
=step_div(dj
-ey
,ny
);
583 int qua
=di
+step_int(-ima
*bxy
*xsp
),quadiv
=step_div(qua
,nx
);
584 int fi
=qua
-quadiv
*nx
,fijk
=fi
+nx
*(dj
-ima
*ny
+oy
*dk
);
585 double dis
=ima
*bxy
+quadiv
*bx
,switchx
=di
*boxx
-ima
*bxy
-quadiv
*bx
,adis
;
587 // Left image computation
588 if((img
[dijk
]&1)==0) {
590 odijk
=dijk
-1;adis
=dis
;
592 odijk
=dijk
+nx
-1;adis
=dis
+bx
;
595 for(l
=0;l
<co
[fijk
];l
++) {
596 if(p
[fijk
][ps
*l
]>switchx
) put_image(dijk
,fijk
,l
,dis
,by
*ima
,0);
597 else put_image(odijk
,fijk
,l
,adis
,by
*ima
,0);
601 // Right image computation
602 if((img
[dijk
]&2)==0) {
604 fijk
+=1-nx
;switchx
+=(1-nx
)*boxx
;dis
+=bx
;
606 fijk
++;switchx
+=boxx
;
609 odijk
=dijk
-nx
+1;adis
=dis
-bx
;
611 odijk
=dijk
+1;adis
=dis
;
614 for(l
=0;l
<co
[fijk
];l
++) {
615 if(p
[fijk
][ps
*l
]<switchx
) put_image(dijk
,fijk
,l
,dis
,by
*ima
,0);
616 else put_image(odijk
,fijk
,l
,adis
,by
*ima
,0);
620 // All contributions to the block now added, so set both two bits of
621 // the image information
625 /** Creates particles within an image block that is not aligned with the
626 * primary domain in the z axis. In this case, the image block may be comprised
627 * of particles from four primary blocks. The routine considers these four
628 * primary blocks, and adds the needed particles to the image. The remaining
629 * particles from the primary blocks are also filled into the neighboring
631 * \param[in] (di,dj,dk) the index of the block to consider. The z index must
632 * satisfy dk<ez or dk>=wz. */
633 void container_periodic_base::create_vertical_image(int di
,int dj
,int dk
) {
634 int l
,dijk
=di
+nx
*(dj
+oy
*dk
),dijkl
,dijkr
,ima
=step_div(dk
-ez
,nz
);
635 int qj
=dj
+step_int(-ima
*byz
*ysp
),qjdiv
=step_div(qj
-ey
,ny
);
636 int qi
=di
+step_int((-ima
*bxz
-qjdiv
*bxy
)*xsp
),qidiv
=step_div(qi
,nx
);
637 int fi
=qi
-qidiv
*nx
,fj
=qj
-qjdiv
*ny
,fijk
=fi
+nx
*(fj
+oy
*(dk
-ima
*nz
)),fijk2
;
638 double disy
=ima
*byz
+qjdiv
*by
,switchy
=(dj
-ey
)*boxy
-ima
*byz
-qjdiv
*by
;
639 double disx
=ima
*bxz
+qjdiv
*bxy
+qidiv
*bx
,switchx
=di
*boxx
-ima
*bxz
-qjdiv
*bxy
-qidiv
*bx
;
640 double switchx2
,disxl
,disxr
,disx2
,disxr2
;
642 if(di
==0) {dijkl
=dijk
+nx
-1;disxl
=disx
+bx
;}
643 else {dijkl
=dijk
-1;disxl
=disx
;}
645 if(di
==nx
-1) {dijkr
=dijk
-nx
+1;disxr
=disx
-bx
;}
646 else {dijkr
=dijk
+1;disxr
=disx
;}
648 // Down-left image computation
650 if((img
[dijk
]&1)==0) {
656 for(l
=0;l
<co
[fijk
];l
++) {
657 if(p
[fijk
][ps
*l
+1]>switchy
) {
658 if(p
[fijk
][ps
*l
]>switchx
) put_image(dijk
,fijk
,l
,disx
,disy
,bz
*ima
);
659 else put_image(dijkl
,fijk
,l
,disxl
,disy
,bz
*ima
);
661 if(!y_exist
) continue;
662 if(p
[fijk
][ps
*l
]>switchx
) put_image(dijk
-nx
,fijk
,l
,disx
,disy
,bz
*ima
);
663 else put_image(dijkl
-nx
,fijk
,l
,disxl
,disy
,bz
*ima
);
668 // Down-right image computation
669 if((img
[dijk
]&2)==0) {
671 fijk2
=fijk
+1-nx
;switchx2
=switchx
+(1-nx
)*boxx
;disx2
=disx
+bx
;disxr2
=disxr
+bx
;
673 fijk2
=fijk
+1;switchx2
=switchx
+boxx
;disx2
=disx
;disxr2
=disxr
;
680 for(l
=0;l
<co
[fijk2
];l
++) {
681 if(p
[fijk2
][ps
*l
+1]>switchy
) {
682 if(p
[fijk2
][ps
*l
]>switchx2
) put_image(dijkr
,fijk2
,l
,disxr2
,disy
,bz
*ima
);
683 else put_image(dijk
,fijk2
,l
,disx2
,disy
,bz
*ima
);
685 if(!y_exist
) continue;
686 if(p
[fijk2
][ps
*l
]>switchx2
) put_image(dijkr
-nx
,fijk2
,l
,disxr2
,disy
,bz
*ima
);
687 else put_image(dijk
-nx
,fijk2
,l
,disx2
,disy
,bz
*ima
);
692 // Recomputation of some intermediate quantities for boundary cases
695 switchy
+=(1-ny
)*boxy
;
697 qi
=di
+step_int(-(ima
*bxz
+(qjdiv
+1)*bxy
)*xsp
);
698 int dqidiv
=step_div(qi
,nx
)-qidiv
;qidiv
+=dqidiv
;
702 disxl
+=bxy
+bx
*dqidiv
;
703 disxr
+=bxy
+bx
*dqidiv
;
704 switchx
-=bxy
+bx
*dqidiv
;
706 fijk
+=nx
;switchy
+=boxy
;
709 // Up-left image computation
711 if((img
[dijk
]&4)==0) {
717 for(l
=0;l
<co
[fijk
];l
++) {
718 if(p
[fijk
][ps
*l
+1]>switchy
) {
719 if(!y_exist
) continue;
720 if(p
[fijk
][ps
*l
]>switchx
) put_image(dijk
+nx
,fijk
,l
,disx
,disy
,bz
*ima
);
721 else put_image(dijkl
+nx
,fijk
,l
,disxl
,disy
,bz
*ima
);
723 if(p
[fijk
][ps
*l
]>switchx
) put_image(dijk
,fijk
,l
,disx
,disy
,bz
*ima
);
724 else put_image(dijkl
,fijk
,l
,disxl
,disy
,bz
*ima
);
729 // Up-right image computation
730 if((img
[dijk
]&8)==0) {
732 fijk2
=fijk
+1-nx
;switchx2
=switchx
+(1-nx
)*boxx
;disx2
=disx
+bx
;disxr2
=disxr
+bx
;
734 fijk2
=fijk
+1;switchx2
=switchx
+boxx
;disx2
=disx
;disxr2
=disxr
;
741 for(l
=0;l
<co
[fijk2
];l
++) {
742 if(p
[fijk2
][ps
*l
+1]>switchy
) {
743 if(!y_exist
) continue;
744 if(p
[fijk2
][ps
*l
]>switchx2
) put_image(dijkr
+nx
,fijk2
,l
,disxr2
,disy
,bz
*ima
);
745 else put_image(dijk
+nx
,fijk2
,l
,disx2
,disy
,bz
*ima
);
747 if(p
[fijk2
][ps
*l
]>switchx2
) put_image(dijkr
,fijk2
,l
,disxr2
,disy
,bz
*ima
);
748 else put_image(dijk
,fijk2
,l
,disx2
,disy
,bz
*ima
);
753 // All contributions to the block now added, so set all four bits of
754 // the image information
758 /** Copies a particle position from the primary domain into an image block.
759 * \param[in] reg the block index within the primary domain that the particle
761 * \param[in] fijk the index of the image block.
762 * \param[in] l the index of the particle entry within the primary block.
763 * \param[in] (dx,dy,dz) the displacement vector to add to the particle. */
764 void container_periodic_base::put_image(int reg
,int fijk
,int l
,double dx
,double dy
,double dz
) {
765 if(co
[reg
]==mem
[reg
]) add_particle_memory(reg
);
766 double *p1
=p
[reg
]+ps
*co
[reg
],*p2
=p
[fijk
]+ps
*l
;
770 if(ps
==4) *(++p1
)=*(++p2
);
771 id
[reg
][co
[reg
]++]=id
[fijk
][l
];