Strip extra spaces from code.
[voro++.git] / branches / 2d / src / v_connect / container_2d.cc
blob25f06d3c6a69fc866cd9311c469310d21570672c
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
7 /** \file container_2d.cc
8 * \brief Function implementations for the container_2d and related classes. */
10 #include "container_2d.hh"
12 namespace voro {
14 /** The class constructor sets up the geometry of container, initializing the
15 * minimum and maximum coordinates in each direction, and setting whether each
16 * direction is periodic or not. It divides the container into a rectangular
17 * grid of blocks, and allocates memory for each of these for storing particle
18 * positions and IDs.
19 * \param[in] (ax_,bx_) the minimum and maximum x coordinates.
20 * \param[in] (ay_,by_) the minimum and maximum y coordinates.
21 * \param[in] (nx_,ny_) the number of grid blocks in each of the three
22 * coordinate directions.
23 * \param[in] (xperiodic_,yperiodic_) flags setting whether the container is
24 * periodic in each coordinate direction.
25 * \param[in] init_mem the initial memory allocation for each block.
26 * \param[in] ps_ the number of floating point entries to store for each
27 * particle. */
28 container_base_2d::container_base_2d(double ax_,double bx_,double ay_,double by_,
29 int nx_,int ny_,bool xperiodic_,bool yperiodic_,int init_mem,int ps_)
30 : voro_base_2d(nx_,ny_,(bx_-ax_)/nx_,(by_-ay_)/ny_),
31 ax(ax_), bx(bx_), ay(ay_), by(by_), xperiodic(xperiodic_), yperiodic(yperiodic_),
32 id(new int*[nxy]), p(new double*[nxy]), co(new int[nxy]), mem(new int[nxy]), ps(ps_) {
33 int l;
34 full_connect=false;
35 //totpar=0;
36 for(l=0;l<nxy;l++) co[l]=0;
37 for(l=0;l<nxy;l++) mem[l]=init_mem;
38 for(l=0;l<nxy;l++) id[l]=new int[init_mem];
39 for(l=0;l<nxy;l++) p[l]=new double[ps*init_mem];
42 /** The container destructor frees the dynamically allocated memory. */
43 container_base_2d::~container_base_2d() {
44 int l;
45 for(l=nxy-1;l>=0;l--) delete [] p[l];
46 for(l=nxy-1;l>=0;l--) delete [] id[l];
47 delete [] id;
48 delete [] p;
49 delete [] co;
50 delete [] mem;
53 /** The class constructor sets up the geometry of container.
54 * \param[in] (ax_,bx_) the minimum and maximum x coordinates.
55 * \param[in] (ay_,by_) the minimum and maximum y coordinates.
56 * \param[in] (nx_,ny_) the number of grid blocks in each of the three
57 * coordinate directions.
58 * \param[in] (xperiodic_,yperiodic_) flags setting whether the container is
59 * periodic in each coordinate direction.
60 * \param[in] init_mem the initial memory allocation for each block. */
61 container_2d::container_2d(double ax_,double bx_,double ay_,double by_,
62 int nx_,int ny_,bool xperiodic_,bool yperiodic_,int init_mem)
63 : container_base_2d(ax_,bx_,ay_,by_,nx_,ny_,xperiodic_,yperiodic_,init_mem,2),
64 vc(*this,xperiodic_?2*nx_+1:nx_,yperiodic_?2*ny_+1:ny_) {full_connect=false;}
66 /** The class constructor sets up the geometry of container.
67 * \param[in] (ax_,bx_) the minimum and maximum x coordinates.
68 * \param[in] (ay_,by_) the minimum and maximum y coordinates.
69 * \param[in] (nx_,ny_) the number of grid blocks in each of the three
70 * coordinate directions.
71 * \param[in] (xperiodic_,yperiodic_) flags setting whether the container is
72 * periodic in each coordinate direction.
73 * \param[in] init_mem the initial memory allocation for each block. */
74 container_poly_2d::container_poly_2d(double ax_,double bx_,double ay_,double by_,
75 int nx_,int ny_,bool xperiodic_,bool yperiodic_,int init_mem)
76 : container_base_2d(ax_,bx_,ay_,by_,nx_,ny_,xperiodic_,yperiodic_,init_mem,3),
77 vc(*this,xperiodic_?2*nx_+1:nx_,yperiodic_?2*ny_+1:ny_) {ppr=p; full_connect=false;}
79 /** Put a particle into the correct region of the container.
80 * \param[in] n the numerical ID of the inserted particle.
81 * \param[in] (x,y) the position vector of the inserted particle. */
82 void container_2d::put(int n,double x,double y) {
83 int ij;
84 if(put_locate_block(ij,x,y)) {
85 //totpar++;
86 id[ij][co[ij]]=n;
87 double *pp=p[ij]+2*co[ij]++;
88 *(pp++)=x;*pp=y;
92 /** Put a particle into the correct region of the container.
93 * \param[in] n the numerical ID of the inserted particle.
94 * \param[in] (x,y) the position vector of the inserted particle.
95 * \param[in] r the radius of the particle. */
96 void container_poly_2d::put(int n,double x,double y,double r) {
97 int ij;
98 if(put_locate_block(ij,x,y)) {
99 //totpar++;
100 id[ij][co[ij]]=n;
101 double *pp=p[ij]+3*co[ij]++;
102 *(pp++)=x;*(pp++)=y;*pp=r;
103 if(max_radius<r) max_radius=r;
107 /** Put a particle into the correct region of the container, also recording
108 * into which region it was stored.
109 * \param[in] vo the ordering class in which to record the region.
110 * \param[in] n the numerical ID of the inserted particle.
111 * \param[in] (x,y) the position vector of the inserted particle. */
112 void container_2d::put(particle_order &vo,int n,double x,double y) {
113 int ij;
114 if(put_locate_block(ij,x,y)) {
115 //totpar++;
116 id[ij][co[ij]]=n;
117 vo.add(ij,co[ij]);
118 double *pp=p[ij]+2*co[ij]++;
119 *(pp++)=x;*pp=y;
123 /** Put a particle into the correct region of the container, also recording
124 * into which region it was stored.
125 * \param[in] vo the ordering class in which to record the region.
126 * \param[in] n the numerical ID of the inserted particle.
127 * \param[in] (x,y) the position vector of the inserted particle.
128 * \param[in] r the radius of the particle. */
129 void container_poly_2d::put(particle_order &vo,int n,double x,double y,double r) {
130 int ij;
131 if(put_locate_block(ij,x,y)) {
132 //totpar++;
133 id[ij][co[ij]]=n;
134 vo.add(ij,co[ij]);
135 double *pp=p[ij]+3*co[ij]++;
136 *(pp++)=x;*(pp++)=y;*pp=r;
137 if(max_radius<r) max_radius=r;
141 /** This routine takes a particle position vector, tries to remap it into the
142 * primary domain. If successful, it computes the region into which it can be
143 * stored and checks that there is enough memory within this region to store
144 * it.
145 * \param[out] ij the region index.
146 * \param[in,out] (x,y) the particle position, remapped into the primary
147 * domain if necessary.
148 * \return True if the particle can be successfully placed into the container,
149 * false otherwise. */
150 inline bool container_base_2d::put_locate_block(int &ij,double &x,double &y) {
151 if(put_remap(ij,x,y)) {
152 if(co[ij]==mem[ij]) add_particle_memory(ij);
153 return true;
155 #if VOROPP_REPORT_OUT_OF_BOUNDS ==1
156 fprintf(stderr,"Out of bounds: (x,y)=(%g,%g)\n",x,y);
157 #endif
158 return false;
161 /** Takes a particle position vector and computes the region index into which
162 * it should be stored. If the container is periodic, then the routine also
163 * maps the particle position to ensure it is in the primary domain. If the
164 * container is not periodic, the routine bails out.
165 * \param[out] ij the region index.
166 * \param[in,out] (x,y) the particle position, remapped into the primary domain
167 * if necessary.
168 * \return True if the particle can be successfully placed into the container,
169 * false otherwise. */
170 inline bool container_base_2d::put_remap(int &ij,double &x,double &y) {
171 int l;
173 ij=step_int((x-ax)*xsp);
174 if(xperiodic) {l=step_mod(ij,nx);x+=boxx*(l-ij);ij=l;}
175 else if(ij<0||ij>=nx) return false;
177 int j=step_int((y-ay)*ysp);
178 if(yperiodic) {l=step_mod(j,ny);y+=boxy*(l-j);j=l;}
179 else if(j<0||j>=ny) return false;
181 ij+=nx*j;
182 return true;
185 /** Takes a position vector and attempts to remap it into the primary domain.
186 * \param[out] (ai,aj) the periodic image displacement that the vector is in,
187 * with (0,0,0) corresponding to the primary domain.
188 * \param[out] (ci,cj) the index of the block that the position vector is
189 * within, once it has been remapped.
190 * \param[in,out] (x,y) the position vector to consider, which is remapped into
191 * the primary domain during the routine.
192 * \param[out] ij the block index that the vector is within.
193 * \return True if the particle is within the container or can be remapped into
194 * it, false if it lies outside of the container bounds. */
195 inline bool container_base_2d::remap(int &ai,int &aj,int &ci,int &cj,double &x,double &y,int &ij) {
196 ci=step_int((x-ax)*xsp);
197 if(ci<0||ci>=nx) {
198 if(xperiodic) {ai=step_div(ci,nx);x-=ai*(bx-ax);ci-=ai*nx;}
199 else return false;
200 } else ai=0;
202 cj=step_int((y-ay)*ysp);
203 if(cj<0||cj>=ny) {
204 if(yperiodic) {aj=step_div(cj,ny);y-=aj*(by-ay);cj-=aj*ny;}
205 else return false;
206 } else aj=0;
208 ij=ci+nx*cj;
209 return true;
212 /** Takes a vector and finds the particle whose Voronoi cell contains that
213 * vector. This is equivalent to finding the particle which is nearest to the
214 * vector. Additional wall classes are not considered by this routine.
215 * \param[in] (x,y) the vector to test.
216 * \param[out] (rx,ry) the position of the particle whose Voronoi cell contains
217 * the vector. If the container is periodic, this may point
218 * to a particle in a periodic image of the primary domain.
219 * \param[out] pid the ID of the particle.
220 * \return True if a particle was found. If the container has no particles,
221 * then the search will not find a Voronoi cell and false is returned. */
222 bool container_2d::find_voronoi_cell(double x,double y,double &rx,double &ry,int &pid) {
223 int ai,aj,ci,cj,ij;
224 particle_record_2d w;
225 double mrs;
227 // If the given vector lies outside the domain, but the container
228 // is periodic, then remap it back into the domain
229 if(!remap(ai,aj,ci,cj,x,y,ij)) return false;
230 vc.find_voronoi_cell(x,y,ci,cj,ij,w,mrs);
232 if(w.ij!=-1) {
234 // Assemble the position vector of the particle to be returned,
235 // applying a periodic remapping if necessary
236 if(xperiodic) {ci+=w.di;if(ci<0||ci>=nx) ai+=step_div(ci,nx);}
237 if(yperiodic) {cj+=w.dj;if(cj<0||cj>=ny) aj+=step_div(cj,ny);}
238 rx=p[w.ij][2*w.l]+ai*(bx-ax);
239 ry=p[w.ij][2*w.l+1]+aj*(by-ay);
240 pid=id[w.ij][w.l];
241 return true;
244 // If no particle if found then just return false
245 return false;
248 /** Takes a vector and finds the particle whose Voronoi cell contains that
249 * vector. Additional wall classes are not considered by this routine.
250 * \param[in] (x,y) the vector to test.
251 * \param[out] (rx,ry) the position of the particle whose Voronoi cell contains
252 * the vector. If the container is periodic, this may point
253 * to a particle in a periodic image of the primary domain.
254 * \param[out] pid the ID of the particle.
255 * \return True if a particle was found. If the container has no particles,
256 * then the search will not find a Voronoi cell and false is returned. */
257 bool container_poly_2d::find_voronoi_cell(double x,double y,double &rx,double &ry,int &pid) {
258 int ai,aj,ci,cj,ij;
259 particle_record_2d w;
260 double mrs;
262 // If the given vector lies outside the domain, but the container
263 // is periodic, then remap it back into the domain
264 if(!remap(ai,aj,ci,cj,x,y,ij)) return false;
265 vc.find_voronoi_cell(x,y,ci,cj,ij,w,mrs);
267 if(w.ij!=-1) {
269 // Assemble the position vector of the particle to be returned,
270 // applying a periodic remapping if necessary
271 if(xperiodic) {ci+=w.di;if(ci<0||ci>=nx) ai+=step_div(ci,nx);}
272 if(yperiodic) {cj+=w.dj;if(cj<0||cj>=ny) aj+=step_div(cj,ny);}
273 rx=p[w.ij][3*w.l]+ai*(bx-ax);
274 ry=p[w.ij][3*w.l+1]+aj*(by-ay);
275 pid=id[w.ij][w.l];
276 return true;
279 // If no particle if found then just return false
280 return false;
283 /** Increase memory for a particular region.
284 * \param[in] i the index of the region to reallocate. */
285 void container_base_2d::add_particle_memory(int i) {
286 int l,nmem=mem[i]<<1;
288 // Carry out a check on the memory allocation size, and
289 // print a status message if requested
290 if(nmem>max_particle_memory_2d)
291 voro_fatal_error("Absolute maximum memory allocation exceeded",VOROPP_MEMORY_ERROR);
292 #if VOROPP_VERBOSE >=3
293 fprintf(stderr,"Particle memory in region %d scaled up to %d\n",i,nmem);
294 #endif
296 // Allocate new memory and copy in the contents of the old arrays
297 int *idp=new int[nmem];
298 for(l=0;l<co[i];l++) idp[l]=id[i][l];
299 double *pp=new double[ps*nmem];
300 for(l=0;l<ps*co[i];l++) pp[l]=p[i][l];
302 // Update pointers and delete old arrays
303 mem[i]=nmem;
304 delete [] id[i];id[i]=idp;
305 delete [] p[i];p[i]=pp;
308 /** Import a list of particles from an open file stream into the container.
309 * Entries of four numbers (Particle ID, x position, y position, z position)
310 * are searched for. If the file cannot be successfully read, then the routine
311 * causes a fatal error.
312 * \param[in] fp the file handle to read from. */
313 void container_2d::import(FILE *fp) {
314 int i,j;
315 double x,y;
316 while((j=fscanf(fp,"%d %lg %lg",&i,&x,&y))==3) put(i,x,y);
317 if(j!=EOF) voro_fatal_error("File import error",VOROPP_FILE_ERROR);
320 /** Import a list of particles from an open file stream, also storing the order
321 * of that the particles are read. Entries of four numbers (Particle ID, x
322 * position, y position, z position) are searched for. If the file cannot be
323 * successfully read, then the routine causes a fatal error.
324 * \param[in,out] vo a reference to an ordering class to use.
325 * \param[in] fp the file handle to read from. */
326 void container_2d::import(particle_order &vo,FILE *fp) {
327 int i,j;
328 double x,y;
329 while((j=fscanf(fp,"%d %lg %lg",&i,&x,&y))==3) put(vo,i,x,y);
330 if(j!=EOF) voro_fatal_error("File import error",VOROPP_FILE_ERROR);
333 /** Import a list of particles from an open file stream into the container.
334 * Entries of five numbers (Particle ID, x position, y position, z position,
335 * radius) are searched for. If the file cannot be successfully read, then the
336 * routine causes a fatal error.
337 * \param[in] fp the file handle to read from. */
338 void container_poly_2d::import(FILE *fp) {
339 int i,j;
340 double x,y,r;
341 while((j=fscanf(fp,"%d %lg %lg %lg",&i,&x,&y,&r))==4) put(i,x,y,r);
342 if(j!=EOF) voro_fatal_error("File import error",VOROPP_FILE_ERROR);
345 /** Import a list of particles from an open file stream, also storing the order
346 * of that the particles are read. Entries of four numbers (Particle ID, x
347 * position, y position, z position, radius) are searched for. If the file
348 * cannot be successfully read, then the routine causes a fatal error.
349 * \param[in,out] vo a reference to an ordering class to use.
350 * \param[in] fp the file handle to read from. */
351 void container_poly_2d::import(particle_order &vo,FILE *fp) {
352 int i,j;
353 double x,y,r;
354 while((j=fscanf(fp,"%d %lg %lg %lg",&i,&x,&y,&r))==4) put(vo,i,x,y,r);
355 if(j!=EOF) voro_fatal_error("File import error",VOROPP_FILE_ERROR);
358 /** Outputs the a list of all the container regions along with the number of
359 * particles stored within each. */
360 void container_base_2d::region_count() {
361 int i,j,*cop=co;
362 for(j=0;j<ny;j++) for(i=0;i<nx;i++)
363 printf("Region (%d,%d): %d particles\n",i,j,*(cop++));
366 /** Clears a container of particles. */
367 void container_2d::clear() {
368 for(int *cop=co;cop<co+nxy;cop++) *cop=0;
371 /** Clears a container of particles, also clearing resetting the maximum radius
372 * to zero. */
373 void container_poly_2d::clear() {
374 for(int *cop=co;cop<co+nxy;cop++) *cop=0;
375 max_radius=0;
378 /** Computes all the Voronoi cells and saves customized information about them.
379 * \param[in] format the custom output string to use.
380 * \param[in] fp a file handle to write to. */
381 void container_2d::print_custom(const char *format,FILE *fp) {
382 c_loop_all_2d vl(*this);
383 print_custom(vl,format,fp);
386 /** Computes all the Voronoi cells and saves customized
387 * information about them.
388 * \param[in] format the custom output string to use.
389 * \param[in] fp a file handle to write to. */
390 void container_poly_2d::print_custom(const char *format,FILE *fp) {
391 c_loop_all_2d vl(*this);
392 print_custom(vl,format,fp);
395 /** Computes all the Voronoi cells and saves customized information about them.
396 * \param[in] format the custom output string to use.
397 * \param[in] filename the name of the file to write to. */
398 void container_2d::print_custom(const char *format,const char *filename) {
399 FILE *fp=safe_fopen(filename,"w");
400 print_custom(format,fp);
401 fclose(fp);
404 /** Computes all the Voronoi cells and saves customized
405 * information about them
406 * \param[in] format the custom output string to use.
407 * \param[in] filename the name of the file to write to. */
408 void container_poly_2d::print_custom(const char *format,const char *filename) {
409 FILE *fp=safe_fopen(filename,"w");
410 print_custom(format,fp);
411 fclose(fp);
414 /** Computes all of the Voronoi cells in the container, but does nothing
415 * with the output. It is useful for measuring the pure computation time
416 * of the Voronoi algorithm, without any additional calculations such as
417 * volume evaluation or cell output. */
418 void container_2d::compute_all_cells() {
419 voronoicell_2d c;
420 c_loop_all_2d vl(*this);
421 if(vl.start()) do compute_cell(c,vl);
422 while(vl.inc());
425 /** Computes all of the Voronoi cells in the container, but does nothing
426 * with the output. It is useful for measuring the pure computation time
427 * of the Voronoi algorithm, without any additional calculations such as
428 * volume evaluation or cell output. */
429 void container_poly_2d::compute_all_cells() {
430 voronoicell_2d c;
431 c_loop_all_2d vl(*this);
432 if(vl.start()) do compute_cell(c,vl);while(vl.inc());
435 /** Calculates all of the Voronoi cells and sums their volumes. In most cases
436 * without walls, the sum of the Voronoi cell volumes should equal the volume
437 * of the container to numerical precision.
438 * \return The sum of all of the computed Voronoi volumes. */
439 double container_2d::sum_cell_areas() {
440 voronoicell_2d c;
441 double area=0;
442 c_loop_all_2d vl(*this);
443 if(vl.start()) do if(compute_cell(c,vl)) area+=c.area();while(vl.inc());
444 return area;
447 /** Calculates all of the Voronoi cells and sums their volumes. In most cases
448 * without walls, the sum of the Voronoi cell volumes should equal the volume
449 * of the container to numerical precision.
450 * \return The sum of all of the computed Voronoi volumes. */
451 double container_poly_2d::sum_cell_areas() {
452 voronoicell_2d c;
453 double area=0;
454 c_loop_all_2d vl(*this);
455 if(vl.start()) do if(compute_cell(c,vl)) area+=c.area();while(vl.inc());
456 return area;
459 /** This function tests to see if a given vector lies within the container
460 * bounds and any walls.
461 * \param[in] (x,y) the position vector to be tested.
462 * \return True if the point is inside the container, false if the point is
463 * outside. */
464 bool container_base_2d::point_inside(double x,double y) {
465 if(x<ax||x>bx||y<ay||y>by) return false;
466 return point_inside_walls(x,y);
469 /** Draws an outline of the domain in gnuplot format.
470 * \param[in] fp the file handle to write to. */
471 void container_base_2d::draw_domain_gnuplot(FILE *fp) {
472 fprintf(fp,"%g %g\n%g %g\n%g %g\n%g %g\n%g %g\n",ax,ay,bx,ay,bx,by,ax,by,ax,ay);
475 /** Draws an outline of the domain in POV-Ray format.
476 * \param[in] fp the file handle to write to. */
477 void container_base_2d::draw_domain_pov(FILE *fp) {
478 fprintf(fp,"cylinder{<%g,%g,0>,<%g,%g,0>,rr}\n"
479 "cylinder{<%g,%g,0>,<%g,%g,0>,rr}\n",ax,ay,bx,ay,ax,by,bx,by);
480 fprintf(fp,"cylinder{<%g,%g,0>,<%g,%g,0>,rr}\n"
481 "cylinder{<%g,%g,0>,<%g,%g,0>,rr}\n",ax,ay,ax,by,bx,ay,bx,by);
482 fprintf(fp,"sphere{<%g,%g,0>,rr}\nsphere{<%g,%g,0>,rr}\n"
483 "sphere{<%g,%g,0>,rr}\nsphere{<%g,%g,0>,rr}\n",ax,ay,bx,ay,ax,by,bx,by);
487 /** The wall_list constructor sets up an array of pointers to wall classes. */
488 wall_list_2d::wall_list_2d() : walls(new wall_2d*[init_wall_size]), wep(walls), wel(walls+init_wall_size),
489 current_wall_size(init_wall_size) {}
491 /** The wall_list destructor frees the array of pointers to the wall classes.
493 wall_list_2d::~wall_list_2d() {
494 delete [] walls;
497 /** Adds all of the walls on another wall_list to this class.
498 * \param[in] wl a reference to the wall class. */
499 void wall_list_2d::add_wall(wall_list_2d &wl) {
500 for(wall_2d **wp=wl.walls;wp<wl.wep;wp++) add_wall(*wp);
503 /** Deallocates all of the wall classes pointed to by the wall_list. */
504 void wall_list_2d::deallocate() {
505 for(wall_2d **wp=walls;wp<wep;wp++) delete *wp;
508 /** Increases the memory allocation for the walls array. */
509 void wall_list_2d::increase_wall_memory() {
510 current_wall_size<<=1;
511 if(current_wall_size>max_wall_size)
512 voro_fatal_error("Wall memory allocation exceeded absolute maximum",VOROPP_MEMORY_ERROR);
513 wall_2d **nwalls=new wall_2d*[current_wall_size],**nwp=nwalls,**wp=walls;
514 while(wp<wep) *(nwp++)=*(wp++);
515 delete [] walls;
516 walls=nwalls;wel=walls+current_wall_size;wep=nwp;