Voro++
container_prd.cc
Go to the documentation of this file.
1 // Voro++, a 3D cell-based Voronoi library
2 //
3 // Author : Chris H. Rycroft (LBL / UC Berkeley)
4 // Email : chr@alum.mit.edu
5 // Date : August 30th 2011
6 
7 /** \file container_prd.cc
8  * \brief Function implementations for the container_periodic_base and
9  * related classes. */
10 
11 #include "container_prd.hh"
12 
13 namespace voro {
14 
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
19  * positions and IDs.
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
23  * vector.
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
28  * particle. */
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_), voro_base(nx_,ny_,nz_,bx_/nx_,by_/ny_,bz_/nz_),
32  ey(int(max_uv_y*ysp+1)), ez(int(max_uv_z*zsp+1)), wy(ny+ey), wz(nz+ez),
33  oy(ny+2*ey), oz(nz+2*ez), oxyz(nx*oy*oz), id(new int*[oxyz]), p(new double*[oxyz]),
34  co(new int[oxyz]), mem(new int[oxyz]), img(new char[oxyz]), init_mem(init_mem_), ps(ps_) {
35  int i,j,k,l;
36 
37  // Clear the global arrays
38  int *pp=co;while(pp<co+oxyz) *(pp++)=0;
39  pp=mem;while(pp<mem+oxyz) *(pp++)=0;
40  char *cp=img;while(cp<img+oxyz) *(cp++)=0;
41 
42  // Set up memory for the blocks in the primary domain
43  for(k=ez;k<wz;k++) for(j=ey;j<wy;j++) for(i=0;i<nx;i++) {
44  l=i+nx*(j+oy*k);
45  mem[l]=init_mem;
46  id[l]=new int[init_mem];
47  p[l]=new double[ps*init_mem];
48  }
49 }
50 
51 /** The container destructor frees the dynamically allocated memory. */
53  for(int l=oxyz-1;l>=0;l--) if(mem[l]>0) {
54  delete [] p[l];
55  delete [] id[l];
56  }
57  delete [] img;
58  delete [] mem;
59  delete [] co;
60  delete [] id;
61  delete [] p;
62 }
63 
64 /** The class constructor sets up the geometry of container.
65  * \param[in] (bx_) The x coordinate of the first unit vector.
66  * \param[in] (bxy_,by_) The x and y coordinates of the second unit vector.
67  * \param[in] (bxz_,byz_,bz_) The x, y, and z coordinates of the third unit
68  * vector.
69  * \param[in] (nx_,ny_,nz_) the number of grid blocks in each of the three
70  * coordinate directions.
71  * \param[in] init_mem_ the initial memory allocation for each block. */
72 container_periodic::container_periodic(double bx_,double bxy_,double by_,double bxz_,double byz_,double bz_,
73  int nx_,int ny_,int nz_,int init_mem_)
74  : container_periodic_base(bx_,bxy_,by_,bxz_,byz_,bz_,nx_,ny_,nz_,init_mem_,3),
75  vc(*this,2*nx_+1,2*ey+1,2*ez+1) {}
76 
77 /** The class constructor sets up the geometry of container.
78  * \param[in] (bx_) The x coordinate of the first unit vector.
79  * \param[in] (bxy_,by_) The x and y coordinates of the second unit vector.
80  * \param[in] (bxz_,byz_,bz_) The x, y, and z coordinates of the third unit
81  * vector.
82  * \param[in] (nx_,ny_,nz_) the number of grid blocks in each of the three
83  * coordinate directions.
84  * \param[in] init_mem_ the initial memory allocation for each block. */
85 container_periodic_poly::container_periodic_poly(double bx_,double bxy_,double by_,double bxz_,double byz_,double bz_,
86  int nx_,int ny_,int nz_,int init_mem_)
87  : container_periodic_base(bx_,bxy_,by_,bxz_,byz_,bz_,nx_,ny_,nz_,init_mem_,4),
88  vc(*this,2*nx_+1,2*ey+1,2*ez+1) {ppr=p;}
89 
90 /** Put a particle into the correct region of the container.
91  * \param[in] n the numerical ID of the inserted particle.
92  * \param[in] (x,y,z) the position vector of the inserted particle. */
93 void container_periodic::put(int n,double x,double y,double z) {
94  int ijk;
95  put_locate_block(ijk,x,y,z);
96  id[ijk][co[ijk]]=n;
97  double *pp=p[ijk]+3*co[ijk]++;
98  *(pp++)=x;*(pp++)=y;*pp=z;
99 }
100 
101 /** Put a particle into the correct region of the container.
102  * \param[in] n the numerical ID of the inserted particle.
103  * \param[in] (x,y,z) the position vector of the inserted particle.
104  * \param[in] r the radius of the particle. */
105 void container_periodic_poly::put(int n,double x,double y,double z,double r) {
106  int ijk;
107  put_locate_block(ijk,x,y,z);
108  id[ijk][co[ijk]]=n;
109  double *pp=p[ijk]+4*co[ijk]++;
110  *(pp++)=x;*(pp++)=y;*(pp++)=z;*pp=r;
111  if(max_radius<r) max_radius=r;
112 }
113 
114 /** Put a particle into the correct region of the container.
115  * \param[in] n the numerical ID of the inserted particle.
116  * \param[in] (x,y,z) the position vector of the inserted particle.
117  * \param[out] (ai,aj,ak) the periodic image displacement that the particle is
118  * in, with (0,0,0) corresponding to the primary domain.
119  */
120 void container_periodic::put(int n,double x,double y,double z,int &ai,int &aj,int &ak) {
121  int ijk;
122  put_locate_block(ijk,x,y,z,ai,aj,ak);
123  id[ijk][co[ijk]]=n;
124  double *pp=p[ijk]+3*co[ijk]++;
125  *(pp++)=x;*(pp++)=y;*pp=z;
126 }
127 
128 /** Put a particle into the correct region of the container.
129  * \param[in] n the numerical ID of the inserted particle.
130  * \param[in] (x,y,z) the position vector of the inserted particle.
131  * \param[in] r the radius of the particle.
132  * \param[out] (ai,aj,ak) the periodic image displacement that the particle is
133  * in, with (0,0,0) corresponding to the primary domain.
134  */
135 void container_periodic_poly::put(int n,double x,double y,double z,double r,int &ai,int &aj,int &ak) {
136  int ijk;
137  put_locate_block(ijk,x,y,z,ai,aj,ak);
138  id[ijk][co[ijk]]=n;
139  double *pp=p[ijk]+4*co[ijk]++;
140  *(pp++)=x;*(pp++)=y;*(pp++)=z;*pp=r;
141  if(max_radius<r) max_radius=r;
142 }
143 
144 /** Put a particle into the correct region of the container, also recording
145  * into which region it was stored.
146  * \param[in] vo the ordering class in which to record the region.
147  * \param[in] n the numerical ID of the inserted particle.
148  * \param[in] (x,y,z) the position vector of the inserted particle. */
149 void container_periodic::put(particle_order &vo,int n,double x,double y,double z) {
150  int ijk;
151  put_locate_block(ijk,x,y,z);
152  id[ijk][co[ijk]]=n;
153  vo.add(ijk,co[ijk]);
154  double *pp=p[ijk]+3*co[ijk]++;
155  *(pp++)=x;*(pp++)=y;*pp=z;
156 }
157 
158 /** Put a particle into the correct region of the container, also recording
159  * into which region it was stored.
160  * \param[in] vo the ordering class in which to record the region.
161  * \param[in] n the numerical ID of the inserted particle.
162  * \param[in] (x,y,z) the position vector of the inserted particle.
163  * \param[in] r the radius of the particle. */
164 void container_periodic_poly::put(particle_order &vo,int n,double x,double y,double z,double r) {
165  int ijk;
166  put_locate_block(ijk,x,y,z);
167  id[ijk][co[ijk]]=n;
168  vo.add(ijk,co[ijk]);
169  double *pp=p[ijk]+4*co[ijk]++;
170  *(pp++)=x;*(pp++)=y;*(pp++)=z;*pp=r;
171  if(max_radius<r) max_radius=r;
172 }
173 
174 /** Takes a particle position vector and computes the region index into which
175  * it should be stored. If the container is periodic, then the routine also
176  * maps the particle position to ensure it is in the primary domain. If the
177  * container is not periodic, the routine bails out.
178  * \param[out] ijk the region index.
179  * \param[in,out] (x,y,z) the particle position, remapped into the primary
180  * domain if necessary.
181  * \return True if the particle can be successfully placed into the container,
182  * false otherwise. */
183 void container_periodic_base::put_locate_block(int &ijk,double &x,double &y,double &z) {
184 
185  // Remap particle in the z direction if necessary
186  int k=step_int(z*zsp);
187  if(k<0||k>=nz) {
188  int ak=step_div(k,nz);
189  z-=ak*bz;y-=ak*byz;x-=ak*bxz;k-=ak*nz;
190  }
191 
192  // Remap particle in the y direction if necessary
193  int j=step_int(y*ysp);
194  if(j<0||j>=ny) {
195  int aj=step_div(j,ny);
196  y-=aj*by;x-=aj*bxy;j-=aj*ny;
197  }
198 
199  // Remap particle in the x direction if necessary
200  ijk=step_int(x*xsp);
201  if(ijk<0||ijk>=nx) {
202  int ai=step_div(ijk,nx);
203  x-=ai*bx;ijk-=ai*nx;
204  }
205 
206  // Compute the block index and check memory allocation
207  j+=ey;k+=ez;
208  ijk+=nx*(j+oy*k);
209  if(co[ijk]==mem[ijk]) add_particle_memory(ijk);
210 }
211 
212 /** Takes a particle position vector and computes the region index into which
213  * it should be stored. If the container is periodic, then the routine also
214  * maps the particle position to ensure it is in the primary domain. If the
215  * container is not periodic, the routine bails out.
216  * \param[out] ijk the region index.
217  * \param[in,out] (x,y,z) the particle position, remapped into the primary
218  * domain if necessary.
219  * \param[out] (ai,aj,ak) the periodic image displacement that the particle is
220  * in, with (0,0,0) corresponding to the primary domain.
221  * \return True if the particle can be successfully placed into the container,
222  * false otherwise. */
223 void container_periodic_base::put_locate_block(int &ijk,double &x,double &y,double &z,int &ai,int &aj,int &ak) {
224 
225  // Remap particle in the z direction if necessary
226  int k=step_int(z*zsp);
227  if(k<0||k>=nz) {
228  ak=step_div(k,nz);
229  z-=ak*bz;y-=ak*byz;x-=ak*bxz;k-=ak*nz;
230  } else ak=0;
231 
232  // Remap particle in the y direction if necessary
233  int j=step_int(y*ysp);
234  if(j<0||j>=ny) {
235  aj=step_div(j,ny);
236  y-=aj*by;x-=aj*bxy;j-=aj*ny;
237  } else aj=0;
238 
239  // Remap particle in the x direction if necessary
240  ijk=step_int(x*xsp);
241  if(ijk<0||ijk>=nx) {
242  ai=step_div(ijk,nx);
243  x-=ai*bx;ijk-=ai*nx;
244  } else ai=0;
245 
246  // Compute the block index and check memory allocation
247  j+=ey;k+=ez;
248  ijk+=nx*(j+oy*k);
249  if(co[ijk]==mem[ijk]) add_particle_memory(ijk);
250 }
251 
252 /** Takes a position vector and remaps it into the primary domain.
253  * \param[out] (ai,aj,ak) the periodic image displacement that the vector is in,
254  * with (0,0,0) corresponding to the primary domain.
255  * \param[out] (ci,cj,ck) the index of the block that the position vector is
256  * within, once it has been remapped.
257  * \param[in,out] (x,y,z) the position vector to consider, which is remapped
258  * into the primary domain during the routine.
259  * \param[out] ijk the block index that the vector is within. */
260 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) {
261 
262  // Remap particle in the z direction if necessary
263  ck=step_int(z*zsp);
264  if(ck<0||ck>=nz) {
265  ak=step_div(ck,nz);
266  z-=ak*bz;y-=ak*byz;x-=ak*bxz;ck-=ak*nz;
267  } else ak=0;
268 
269  // Remap particle in the y direction if necessary
270  cj=step_int(y*ysp);
271  if(cj<0||cj>=ny) {
272  aj=step_div(cj,ny);
273  y-=aj*by;x-=aj*bxy;cj-=aj*ny;
274  } else aj=0;
275 
276  // Remap particle in the x direction if necessary
277  ci=step_int(x*xsp);
278  if(ci<0||ci>=nx) {
279  ai=step_div(ci,nx);
280  x-=ai*bx;ci-=ai*nx;
281  } else ai=0;
282 
283  cj+=ey;ck+=ez;
284  ijk=ci+nx*(cj+oy*ck);
285 }
286 
287 /** Takes a vector and finds the particle whose Voronoi cell contains that
288  * vector. This is equivalent to finding the particle which is nearest to the
289  * vector.
290  * \param[in] (x,y,z) the vector to test.
291  * \param[out] (rx,ry,rz) the position of the particle whose Voronoi cell
292  * contains the vector. This may point to a particle in
293  * a periodic image of the primary domain.
294  * \param[out] pid the ID of the particle.
295  * \return True if a particle was found. If the container has no particles,
296  * then the search will not find a Voronoi cell and false is returned. */
297 bool container_periodic::find_voronoi_cell(double x,double y,double z,double &rx,double &ry,double &rz,int &pid) {
298  int ai,aj,ak,ci,cj,ck,ijk;
299  particle_record w;
300  double mrs;
301 
302  // Remap the vector into the primary domain and then search for the
303  // Voronoi cell that it is within
304  remap(ai,aj,ak,ci,cj,ck,x,y,z,ijk);
305  vc.find_voronoi_cell(x,y,z,ci,cj,ck,ijk,w,mrs);
306 
307  if(w.ijk!=-1) {
308 
309  // Assemble the position vector of the particle to be returned,
310  // applying a periodic remapping if necessary
311  ci+=w.di;if(ci<0||ci>=nx) ai+=step_div(ci,nx);
312  rx=p[w.ijk][3*w.l]+ak*bxz+aj*bxy+ai*bx;
313  ry=p[w.ijk][3*w.l+1]+ak*byz+aj*by;
314  rz=p[w.ijk][3*w.l+2]+ak*bz;
315  pid=id[w.ijk][w.l];
316  return true;
317  }
318  return false;
319 }
320 
321 /** Takes a vector and finds the particle whose Voronoi cell contains that
322  * vector. Additional wall classes are not considered by this routine.
323  * \param[in] (x,y,z) the vector to test.
324  * \param[out] (rx,ry,rz) the position of the particle whose Voronoi cell
325  * contains the vector. If the container is periodic,
326  * this may point to a particle in a periodic image of
327  * the primary domain.
328  * \param[out] pid the ID of the particle.
329  * \return True if a particle was found. If the container has no particles,
330  * then the search will not find a Voronoi cell and false is returned. */
331 bool container_periodic_poly::find_voronoi_cell(double x,double y,double z,double &rx,double &ry,double &rz,int &pid) {
332  int ai,aj,ak,ci,cj,ck,ijk;
333  particle_record w;
334  double mrs;
335 
336  // Remap the vector into the primary domain and then search for the
337  // Voronoi cell that it is within
338  remap(ai,aj,ak,ci,cj,ck,x,y,z,ijk);
339  vc.find_voronoi_cell(x,y,z,ci,cj,ck,ijk,w,mrs);
340 
341  if(w.ijk!=-1) {
342 
343  // Assemble the position vector of the particle to be returned,
344  // applying a periodic remapping if necessary
345  ci+=w.di;if(ci<0||ci>=nx) ai+=step_div(ci,nx);
346  rx=p[w.ijk][4*w.l]+ak*bxz+aj*bxy+ai*bx;
347  ry=p[w.ijk][4*w.l+1]+ak*byz+aj*by;
348  rz=p[w.ijk][4*w.l+2]+ak*bz;
349  pid=id[w.ijk][w.l];
350  return true;
351  }
352  return false;
353 }
354 
355 /** Increase memory for a particular region.
356  * \param[in] i the index of the region to reallocate. */
358 
359  // Handle the case when no memory has been allocated for this block
360  if(mem[i]==0) {
361  mem[i]=init_mem;
362  id[i]=new int[init_mem];
363  p[i]=new double[ps*init_mem];
364  return;
365  }
366 
367  // Otherwise, double the memory allocation for this block. Carry out a
368  // check on the memory allocation size, and print a status message if
369  // requested.
370  int l,nmem(mem[i]<<1);
371  if(nmem>max_particle_memory)
372  voro_fatal_error("Absolute maximum memory allocation exceeded",VOROPP_MEMORY_ERROR);
373 #if VOROPP_VERBOSE >=3
374  fprintf(stderr,"Particle memory in region %d scaled up to %d\n",i,nmem);
375 #endif
376 
377  // Allocate new memory and copy in the contents of the old arrays
378  int *idp=new int[nmem];
379  for(l=0;l<co[i];l++) idp[l]=id[i][l];
380  double *pp=new double[ps*nmem];
381  for(l=0;l<ps*co[i];l++) pp[l]=p[i][l];
382 
383  // Update pointers and delete old arrays
384  mem[i]=nmem;
385  delete [] id[i];id[i]=idp;
386  delete [] p[i];p[i]=pp;
387 }
388 
389 /** Import a list of particles from an open file stream into the container.
390  * Entries of four numbers (Particle ID, x position, y position, z position)
391  * are searched for. If the file cannot be successfully read, then the routine
392  * causes a fatal error.
393  * \param[in] fp the file handle to read from. */
395  int i,j;
396  double x,y,z;
397  while((j=fscanf(fp,"%d %lg %lg %lg",&i,&x,&y,&z))==4) put(i,x,y,z);
398  if(j!=EOF) voro_fatal_error("File import error",VOROPP_FILE_ERROR);
399 }
400 
401 /** Import a list of particles from an open file stream, also storing the order
402  * of that the particles are read. Entries of four numbers (Particle ID, x
403  * position, y position, z position) are searched for. If the file cannot be
404  * successfully read, then the routine causes a fatal error.
405  * \param[in,out] vo a reference to an ordering class to use.
406  * \param[in] fp the file handle to read from. */
408  int i,j;
409  double x,y,z;
410  while((j=fscanf(fp,"%d %lg %lg %lg",&i,&x,&y,&z))==4) put(vo,i,x,y,z);
411  if(j!=EOF) voro_fatal_error("File import error",VOROPP_FILE_ERROR);
412 }
413 
414 /** Import a list of particles from an open file stream into the container.
415  * Entries of five numbers (Particle ID, x position, y position, z position,
416  * radius) are searched for. If the file cannot be successfully read, then the
417  * routine causes a fatal error.
418  * \param[in] fp the file handle to read from. */
420  int i,j;
421  double x,y,z,r;
422  while((j=fscanf(fp,"%d %lg %lg %lg %lg",&i,&x,&y,&z,&r))==5) put(i,x,y,z,r);
423  if(j!=EOF) voro_fatal_error("File import error",VOROPP_FILE_ERROR);
424 }
425 
426 /** Import a list of particles from an open file stream, also storing the order
427  * of that the particles are read. Entries of four numbers (Particle ID, x
428  * position, y position, z position, radius) are searched for. If the file
429  * cannot be successfully read, then the routine causes a fatal error.
430  * \param[in,out] vo a reference to an ordering class to use.
431  * \param[in] fp the file handle to read from. */
433  int i,j;
434  double x,y,z,r;
435  while((j=fscanf(fp,"%d %lg %lg %lg %lg",&i,&x,&y,&z,&r))==5) put(vo,i,x,y,z,r);
436  if(j!=EOF) voro_fatal_error("File import error",VOROPP_FILE_ERROR);
437 }
438 
439 /** Outputs the a list of all the container regions along with the number of
440  * particles stored within each. */
442  int i,j,k,*cop=co;
443  for(k=0;k<nz;k++) for(j=0;j<ny;j++) for(i=0;i<nx;i++)
444  printf("Region (%d,%d,%d): %d particles\n",i,j,k,*(cop++));
445 }
446 
447 /** Clears a container of particles. */
449  for(int *cop=co;cop<co+nxyz;cop++) *cop=0;
450 }
451 
452 /** Clears a container of particles, also clearing resetting the maximum radius
453  * to zero. */
455  for(int *cop=co;cop<co+nxyz;cop++) *cop=0;
456  max_radius=0;
457 }
458 
459 /** Computes all the Voronoi cells and saves customized information about them.
460  * \param[in] format the custom output string to use.
461  * \param[in] fp a file handle to write to. */
462 void container_periodic::print_custom(const char *format,FILE *fp) {
463  c_loop_all_periodic vl(*this);
464  print_custom(vl,format,fp);
465 }
466 
467 /** Computes all the Voronoi cells and saves customized
468  * information about them.
469  * \param[in] format the custom output string to use.
470  * \param[in] fp a file handle to write to. */
471 void container_periodic_poly::print_custom(const char *format,FILE *fp) {
472  c_loop_all_periodic vl(*this);
473  print_custom(vl,format,fp);
474 }
475 
476 /** Computes all the Voronoi cells and saves customized information about them.
477  * \param[in] format the custom output string to use.
478  * \param[in] filename the name of the file to write to. */
479 void container_periodic::print_custom(const char *format,const char *filename) {
480  FILE *fp=safe_fopen(filename,"w");
481  print_custom(format,fp);
482  fclose(fp);
483 }
484 
485 /** Computes all the Voronoi cells and saves customized
486  * information about them
487  * \param[in] format the custom output string to use.
488  * \param[in] filename the name of the file to write to. */
489 void container_periodic_poly::print_custom(const char *format,const char *filename) {
490  FILE *fp=safe_fopen(filename,"w");
491  print_custom(format,fp);
492  fclose(fp);
493 }
494 
495 /** Computes all of the Voronoi cells in the container, but does nothing
496  * with the output. It is useful for measuring the pure computation time
497  * of the Voronoi algorithm, without any additional calculations such as
498  * volume evaluation or cell output. */
500  voronoicell c;
501  c_loop_all_periodic vl(*this);
502  if(vl.start()) do compute_cell(c,vl);
503  while(vl.inc());
504 }
505 
506 /** Computes all of the Voronoi cells in the container, but does nothing
507  * with the output. It is useful for measuring the pure computation time
508  * of the Voronoi algorithm, without any additional calculations such as
509  * volume evaluation or cell output. */
511  voronoicell c;
512  c_loop_all_periodic vl(*this);
513  if(vl.start()) do compute_cell(c,vl);while(vl.inc());
514 }
515 
516 /** Calculates all of the Voronoi cells and sums their volumes. In most cases
517  * without walls, the sum of the Voronoi cell volumes should equal the volume
518  * of the container to numerical precision.
519  * \return The sum of all of the computed Voronoi volumes. */
521  voronoicell c;
522  double vol=0;
523  c_loop_all_periodic vl(*this);
524  if(vl.start()) do if(compute_cell(c,vl)) vol+=c.volume();while(vl.inc());
525  return vol;
526 }
527 
528 /** Calculates all of the Voronoi cells and sums their volumes. In most cases
529  * without walls, the sum of the Voronoi cell volumes should equal the volume
530  * of the container to numerical precision.
531  * \return The sum of all of the computed Voronoi volumes. */
533  voronoicell c;
534  double vol=0;
535  c_loop_all_periodic vl(*this);
536  if(vl.start()) do if(compute_cell(c,vl)) vol+=c.volume();while(vl.inc());
537  return vol;
538 }
539 
540 /** This routine creates all periodic images of the particles. It is meant for
541  * diagnostic purposes only, since usually periodic images are dynamically
542  * created in when they are referenced. */
544  int i,j,k;
545  for(k=0;k<oz;k++) for(j=0;j<oy;j++) for(i=0;i<nx;i++) create_periodic_image(i,j,k);
546 }
547 
548 /** Checks that the particles within each block lie within that block's bounds.
549  * This is useful for diagnosing problems with periodic image computation. */
551  int c,l,i,j,k;
552  double mix,miy,miz,max,may,maz,*pp;
553  for(k=l=0;k<oz;k++) for(j=0;j<oy;j++) for(i=0;i<nx;i++,l++) if(mem[l]>0) {
554 
555  // Compute the block's bounds, adding in a small tolerance
556  mix=i*boxx-tolerance;max=mix+boxx+tolerance;
557  miy=(j-ey)*boxy-tolerance;may=miy+boxy+tolerance;
558  miz=(k-ez)*boxz-tolerance;maz=miz+boxz+tolerance;
559 
560  // Print entries for any particles that lie outside the block's
561  // bounds
562  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)
563  printf("%d %d %d %d %f %f %f %f %f %f %f %f %f\n",
564  id[l][c],i,j,k,*pp,pp[1],pp[2],mix,max,miy,may,miz,maz);
565  }
566 }
567 
568 /** Creates particles within an image block that is aligned with the primary
569  * domain in the z axis. In this case, the image block may be comprised of
570  * particles from two primary blocks. The routine considers these two primary
571  * blocks, and adds the needed particles to the image. The remaining particles
572  * from the primary blocks are also filled into the neighboring images.
573  * \param[in] (di,dj,dk) the index of the block to consider. The z index must
574  * satisfy ez<=dk<wz. */
575 void container_periodic_base::create_side_image(int di,int dj,int dk) {
576  int l,dijk=di+nx*(dj+oy*dk),odijk,ima=step_div(dj-ey,ny);
577  int qua=di+step_int(-ima*bxy*xsp),quadiv=step_div(qua,nx);
578  int fi=qua-quadiv*nx,fijk=fi+nx*(dj-ima*ny+oy*dk);
579  double dis=ima*bxy+quadiv*bx,switchx=di*boxx-ima*bxy-quadiv*bx,adis;
580 
581  // Left image computation
582  if((img[dijk]&1)==0) {
583  if(di>0) {
584  odijk=dijk-1;adis=dis;
585  } else {
586  odijk=dijk+nx-1;adis=dis+bx;
587  }
588  img[odijk]|=2;
589  for(l=0;l<co[fijk];l++) {
590  if(p[fijk][ps*l]>switchx) put_image(dijk,fijk,l,dis,by*ima,0);
591  else put_image(odijk,fijk,l,adis,by*ima,0);
592  }
593  }
594 
595  // Right image computation
596  if((img[dijk]&2)==0) {
597  if(fi==nx-1) {
598  fijk+=1-nx;switchx+=(1-nx)*boxx;dis+=bx;
599  } else {
600  fijk++;switchx+=boxx;
601  }
602  if(di==nx-1) {
603  odijk=dijk-nx+1;adis=dis-bx;
604  } else {
605  odijk=dijk+1;adis=dis;
606  }
607  img[odijk]|=1;
608  for(l=0;l<co[fijk];l++) {
609  if(p[fijk][ps*l]<switchx) put_image(dijk,fijk,l,dis,by*ima,0);
610  else put_image(odijk,fijk,l,adis,by*ima,0);
611  }
612  }
613 
614  // All contributions to the block now added, so set both two bits of
615  // the image information
616  img[dijk]=3;
617 }
618 
619 /** Creates particles within an image block that is not aligned with the
620  * primary domain in the z axis. In this case, the image block may be comprised
621  * of particles from four primary blocks. The routine considers these four
622  * primary blocks, and adds the needed particles to the image. The remaining
623  * particles from the primary blocks are also filled into the neighboring
624  * images.
625  * \param[in] (di,dj,dk) the index of the block to consider. The z index must
626  * satisfy dk<ez or dk>=wz. */
628  int l,dijk=di+nx*(dj+oy*dk),dijkl,dijkr,ima=step_div(dk-ez,nz);
629  int qj=dj+step_int(-ima*byz*ysp),qjdiv=step_div(qj-ey,ny);
630  int qi=di+step_int((-ima*bxz-qjdiv*bxy)*xsp),qidiv=step_div(qi,nx);
631  int fi=qi-qidiv*nx,fj=qj-qjdiv*ny,fijk=fi+nx*(fj+oy*(dk-ima*nz)),fijk2;
632  double disy=ima*byz+qjdiv*by,switchy=(dj-ey)*boxy-ima*byz-qjdiv*by;
633  double disx=ima*bxz+qjdiv*bxy+qidiv*bx,switchx=di*boxx-ima*bxz-qjdiv*bxy-qidiv*bx;
634  double switchx2,disxl,disxr,disx2,disxr2;
635 
636  if(di==0) {dijkl=dijk+nx-1;disxl=disx+bx;}
637  else {dijkl=dijk-1;disxl=disx;}
638 
639  if(di==nx-1) {dijkr=dijk-nx+1;disxr=disx-bx;}
640  else {dijkr=dijk+1;disxr=disx;}
641 
642  // Down-left image computation
643  bool y_exist=dj!=0;
644  if((img[dijk]&1)==0) {
645  img[dijkl]|=2;
646  if(y_exist) {
647  img[dijkl-nx]|=8;
648  img[dijk-nx]|=4;
649  }
650  for(l=0;l<co[fijk];l++) {
651  if(p[fijk][ps*l+1]>switchy) {
652  if(p[fijk][ps*l]>switchx) put_image(dijk,fijk,l,disx,disy,bz*ima);
653  else put_image(dijkl,fijk,l,disxl,disy,bz*ima);
654  } else {
655  if(!y_exist) continue;
656  if(p[fijk][ps*l]>switchx) put_image(dijk-nx,fijk,l,disx,disy,bz*ima);
657  else put_image(dijkl-nx,fijk,l,disxl,disy,bz*ima);
658  }
659  }
660  }
661 
662  // Down-right image computation
663  if((img[dijk]&2)==0) {
664  if(fi==nx-1) {
665  fijk2=fijk+1-nx;switchx2=switchx+(1-nx)*boxx;disx2=disx+bx;disxr2=disxr+bx;
666  } else {
667  fijk2=fijk+1;switchx2=switchx+boxx;disx2=disx;disxr2=disxr;
668  }
669  img[dijkr]|=1;
670  if(y_exist) {
671  img[dijkr-nx]|=4;
672  img[dijk-nx]|=8;
673  }
674  for(l=0;l<co[fijk2];l++) {
675  if(p[fijk2][ps*l+1]>switchy) {
676  if(p[fijk2][ps*l]>switchx2) put_image(dijkr,fijk2,l,disxr2,disy,bz*ima);
677  else put_image(dijk,fijk2,l,disx2,disy,bz*ima);
678  } else {
679  if(!y_exist) continue;
680  if(p[fijk2][ps*l]>switchx2) put_image(dijkr-nx,fijk2,l,disxr2,disy,bz*ima);
681  else put_image(dijk-nx,fijk2,l,disx2,disy,bz*ima);
682  }
683  }
684  }
685 
686  // Recomputation of some intermediate quantities for boundary cases
687  if(fj==wy-1) {
688  fijk+=nx*(1-ny)-fi;
689  switchy+=(1-ny)*boxy;
690  disy+=by;
691  qi=di+step_int(-(ima*bxz+(qjdiv+1)*bxy)*xsp);
692  int dqidiv=step_div(qi,nx)-qidiv;qidiv+=dqidiv;
693  fi=qi-qidiv*nx;
694  fijk+=fi;
695  disx+=bxy+bx*dqidiv;
696  disxl+=bxy+bx*dqidiv;
697  disxr+=bxy+bx*dqidiv;
698  switchx-=bxy+bx*dqidiv;
699  } else {
700  fijk+=nx;switchy+=boxy;
701  }
702 
703  // Up-left image computation
704  y_exist=dj!=oy-1;
705  if((img[dijk]&4)==0) {
706  img[dijkl]|=8;
707  if(y_exist) {
708  img[dijkl+nx]|=2;
709  img[dijk+nx]|=1;
710  }
711  for(l=0;l<co[fijk];l++) {
712  if(p[fijk][ps*l+1]>switchy) {
713  if(!y_exist) continue;
714  if(p[fijk][ps*l]>switchx) put_image(dijk+nx,fijk,l,disx,disy,bz*ima);
715  else put_image(dijkl+nx,fijk,l,disxl,disy,bz*ima);
716  } else {
717  if(p[fijk][ps*l]>switchx) put_image(dijk,fijk,l,disx,disy,bz*ima);
718  else put_image(dijkl,fijk,l,disxl,disy,bz*ima);
719  }
720  }
721  }
722 
723  // Up-right image computation
724  if((img[dijk]&8)==0) {
725  if(fi==nx-1) {
726  fijk2=fijk+1-nx;switchx2=switchx+(1-nx)*boxx;disx2=disx+bx;disxr2=disxr+bx;
727  } else {
728  fijk2=fijk+1;switchx2=switchx+boxx;disx2=disx;disxr2=disxr;
729  }
730  img[dijkr]|=4;
731  if(y_exist) {
732  img[dijkr+nx]|=1;
733  img[dijk+nx]|=2;
734  }
735  for(l=0;l<co[fijk2];l++) {
736  if(p[fijk2][ps*l+1]>switchy) {
737  if(!y_exist) continue;
738  if(p[fijk2][ps*l]>switchx2) put_image(dijkr+nx,fijk2,l,disxr2,disy,bz*ima);
739  else put_image(dijk+nx,fijk2,l,disx2,disy,bz*ima);
740  } else {
741  if(p[fijk2][ps*l]>switchx2) put_image(dijkr,fijk2,l,disxr2,disy,bz*ima);
742  else put_image(dijk,fijk2,l,disx2,disy,bz*ima);
743  }
744  }
745  }
746 
747  // All contributions to the block now added, so set all four bits of
748  // the image information
749  img[dijk]=15;
750 }
751 
752 /** Copies a particle position from the primary domain into an image block.
753  * \param[in] reg the block index within the primary domain that the particle
754  * is within.
755  * \param[in] fijk the index of the image block.
756  * \param[in] l the index of the particle entry within the primary block.
757  * \param[in] (dx,dy,dz) the displacement vector to add to the particle. */
758 void container_periodic_base::put_image(int reg,int fijk,int l,double dx,double dy,double dz) {
759  if(co[reg]==mem[reg]) add_particle_memory(reg);
760  double *p1=p[reg]+ps*co[reg],*p2=p[fijk]+ps*l;
761  *(p1++)=*(p2++)+dx;
762  *(p1++)=*(p2++)+dy;
763  *p1=*p2+dz;
764  if(ps==4) *(++p1)=*(++p2);
765  id[reg][co[reg]++]=id[fijk][l];
766 }
767 
768 }
const double bz
Definition: unitcell.hh:41
const double bx
Definition: unitcell.hh:26
void create_vertical_image(int di, int dj, int dk)
bool find_voronoi_cell(double x, double y, double z, double &rx, double &ry, double &rz, int &pid)
#define VOROPP_MEMORY_ERROR
Definition: config.hh:113
container_periodic_poly(double bx_, double bxy_, double by_, double bxz_, double byz_, double bz_, int nx_, int ny_, int nz_, int init_mem_)
Structure for holding information about a particle.
Definition: v_compute.hh:24
Class containing data structures common across all particle container classes.
Definition: v_base.hh:25
const double boxy
Definition: v_base.hh:43
const double byz
Definition: unitcell.hh:38
void put_image(int reg, int fijk, int l, double dx, double dy, double dz)
void put(int n, double x, double y, double z, double r)
bool find_voronoi_cell(double x, double y, double z, double &rx, double &ry, double &rz, int &pid)
#define VOROPP_FILE_ERROR
Definition: config.hh:109
Class for computation of the unit Voronoi cell associated with a 3D non-rectangular periodic domain...
Definition: unitcell.hh:22
void create_side_image(int di, int dj, int dk)
void put(int n, double x, double y, double z)
void create_periodic_image(int di, int dj, int dk)
void import(FILE *fp=stdin)
container_periodic(double bx_, double bxy_, double by_, double bxz_, double byz_, double bz_, int nx_, int ny_, int nz_, int init_mem_)
Header file for the container_periodic_base and related classes.
const double ysp
Definition: v_base.hh:49
int step_div(int a, int b)
Definition: v_base.hh:81
void print_custom(c_loop &vl, const char *format, FILE *fp)
const int nxyz
Definition: v_base.hh:39
bool compute_cell(v_cell &c, c_loop &vl)
const double boxx
Definition: v_base.hh:41
const double by
Definition: unitcell.hh:32
container_periodic_base(double bx_, double bxy_, double by_, double bxz_, double byz_, double bz_, int nx_, int ny_, int nz_, int init_mem_, int ps)
const double boxz
Definition: v_base.hh:45
const double xsp
Definition: v_base.hh:47
void add(int ijk, int q)
Definition: c_loops.hh:63
void put_locate_block(int &ijk, double &x, double &y, double &z)
const double zsp
Definition: v_base.hh:51
void remap(int &ai, int &aj, int &ak, int &ci, int &cj, int &ck, double &x, double &y, double &z, int &ijk)
void import(FILE *fp=stdin)
const double bxy
Definition: unitcell.hh:29
Extension of the voronoicell_base class to represent a Voronoi cell without neighbor information...
Definition: cell.hh:300
const double bxz
Definition: unitcell.hh:35
A class for looping over all particles in a container_periodic or container_periodic_poly class...
Definition: c_loops.hh:325
bool compute_cell(v_cell &c, c_loop &vl)
const int ny
Definition: v_base.hh:30
int step_int(double a)
Definition: v_base.hh:67
A class for storing ordering information when particles are added to a container. ...
Definition: c_loops.hh:37
const int nz
Definition: v_base.hh:32
void print_custom(c_loop &vl, const char *format, FILE *fp)
Class for representing a particle system in a 3D periodic non-orthogonal periodic domain...
const int nx
Definition: v_base.hh:28