1 /** \file container_2d.cc
2 * \brief Function implementations for the container_2d class. */
4 #include "container_2d.hh"
11 /** The class constructor sets up the geometry of container, initializing the
12 * minimum and maximum coordinates in each direction, and setting whether each
13 * direction is periodic or not. It divides the container into a rectangular
14 * grid of blocks, and allocates memory for each of these for storing particle
16 * \param[in] (ax_,bx_) the minimum and maximum x coordinates.
17 * \param[in] (ay_,by_) the minimum and maximum y coordinates.
18 * \param[in] (nx_,ny_) the number of grid blocks in each of the three
19 * coordinate directions.
20 * \param[in] (xperiodic_,yperiodic_) flags setting whether the container is periodic
21 * in each coordinate direction.
22 * \param[in] init_mem the initial memory allocation for each block. */
23 container_2d::container_2d(double ax_
,double bx_
,double ay_
,
24 double by_
,int nx_
,int ny_
,bool xperiodic_
,bool yperiodic_
,bool convex_
,int init_mem
)
25 : ax(ax_
), bx(bx_
), ay(ay_
), by(by_
), boxx((bx_
-ax_
)/nx_
), boxy((by_
-ay_
)/ny_
),
26 xsp(1/boxx
), ysp(1/boxy
), nx(nx_
), ny(ny_
), nxy(nx
*ny
),
27 xperiodic(xperiodic_
), yperiodic(yperiodic_
), convex(convex_
),
28 co(new int[nxy
]), mem(new int[nxy
]), id(new int*[nxy
]),
29 wid(new int*[nxy
]), p(new double*[nxy
]), nlab(new unsigned int*[nxy
]),
30 plab(new int**[nxy
]), soi(NULL
), noofbnds(0), bnds_size(init_bnds_size
),
31 bnds(new double[2*bnds_size
]), edb(new int[50]), bndpts(new int*[nxy
]) {
35 for(l
=0;l
<nxy
;l
++) co
[l
]=0;
36 for(l
=0;l
<nxy
;l
++) mem
[l
]=init_mem
;
38 id
[l
]=new int[init_mem
];
39 bndpts
[l
]=new int[init_mem
];
41 for(l
=0;l
<nxy
;l
++) p
[l
]=new double[2*init_mem
];
46 for(l
=0;l
<nxy
;l
++) nlab
[l
]=new unsigned int[init_mem
];
47 for(l
=0;l
<nxy
;l
++) plab
[l
]=new int*[init_mem
];
50 /** The container destructor frees the dynamically allocated memory. */
51 container_2d::~container_2d() {
54 // Clear "sphere of influence" array if it has been allocated
55 if(soi
!=NULL
) delete [] soi
;
57 // Delete the boundary arrays
61 // Deallocate the block-level arrays
62 for(l
=nxy
-1;l
>=0;l
--) delete [] plab
[l
];
63 for(l
=nxy
-1;l
>=0;l
--) delete [] nlab
[l
];
64 for(l
=nxy
-1;l
>=0;l
--) delete [] wid
[l
];
65 for(l
=nxy
-1;l
>=0;l
--) delete [] p
[l
];
66 for(l
=nxy
-1;l
>=0;l
--) delete [] id
[l
];
68 // Delete the two-dimensional arrays
78 /** Put a particle into the correct region of the container.
79 * \param[in] n the numerical ID of the inserted particle.
80 * \param[in] (x,y) the position vector of the inserted particle. */
81 void container_2d::put(int n
,double x
,double y
, int boundloc
) {
83 if(put_locate_block(ij
,x
,y
)) {
85 bndpts
[ij
][co
[ij
]]=boundloc
;
86 double *pp(p
[ij
]+2*co
[ij
]++);
91 /** This routine takes a particle position vector, tries to remap it into the
92 * primary domain. If successful, it computes the region into which it can be
93 * stored and checks that there is enough memory within this region to store
95 * \param[out] ij the region index.
96 * \param[in,out] (x,y) the particle position, remapped into the primary
97 * domain if necessary.
98 * \return True if the particle can be successfully placed into the container,
100 inline bool container_2d::put_locate_block(int &ij
,double &x
,double &y
) {
101 if(put_remap(ij
,x
,y
)) {
102 if(co
[ij
]==mem
[ij
]) add_particle_memory(ij
);
105 #if VOROPP_REPORT_OUT_OF_BOUNDS ==1
106 fprintf(stderr
,"Out of bounds: (x,y)=(%g,%g)\n",x
,y
);
111 /** Takes a particle position vector and computes the region index into which
112 * it should be stored. If the container is periodic, then the routine also
113 * maps the particle position to ensure it is in the primary domain. If the
114 * container is not periodic, the routine bails out.
115 * \param[out] ij the region index.
116 * \param[in,out] (x,y) the particle position, remapped into the primary
117 * domain if necessary.
118 * \return True if the particle can be successfully placed into the container,
119 * false otherwise. */
120 inline bool container_2d::put_remap(int &ij
,double &x
,double &y
) {
123 ij
=step_int((x
-ax
)*xsp
);
124 if(xperiodic
) {l
=step_mod(ij
,nx
);x
+=boxx
*(l
-ij
);ij
=l
;}
125 else if(ij
<0||ij
>=nx
) return false;
127 int j(step_int((y
-ay
)*ysp
));
128 if(yperiodic
) {l
=step_mod(j
,ny
);y
+=boxy
*(l
-j
);j
=l
;}
129 else if(j
<0||j
>=ny
) return false;
135 /** This does the additional set-up for non-convex containers. We assume that
136 * **p, **id, *co, *mem, *bnds, and noofbnds have already been setup. We then
137 * proceed to setup **wid, *soi, and THE PROBLEM POINTS BOOLEAN ARRAY.
138 * This algorithm keeps the importing seperate from the set-up */
139 void container_2d::setup(){
140 probpts
=new bool[noofbnds
];
141 extpts
=new bool[noofbnds
];
142 double lx
, ly
, cx
, cy
, nx
, ny
;//last (x,y), current (x,y), next (x,y)
143 int widl
=1, maxwid
=1, fwid
=1, nwid
, lwid
;
146 tmp
=tmpp
=new int[3*init_temp_label_size
];
147 tmpe
=tmp
+3*init_temp_label_size
;
149 while(widl
!=noofbnds
){
151 cx
=bnds
[2*widl
]; cy
=bnds
[2*widl
+1];
152 nwid
=edb
[2*widl
]; lwid
=edb
[2*widl
+1];
153 lx
=bnds
[lwid
*2]; ly
=bnds
[lwid
*2+1];
154 nx
=bnds
[2*nwid
]; ny
=bnds
[2*nwid
+1];
156 tag_walls(cx
,cy
,nx
,ny
,widl
);
157 semi_circle_labelling(cx
,cy
,nx
,ny
,widl
);
159 //make sure that the cos(angle)>1 and the angle points inward
160 if(((((lx
-cx
)*(nx
-cx
))+((ly
-cy
)*(ny
-cy
)))>tolerance
) &&
161 (crossproductz(lx
-cx
,ly
-cy
,nx
-cx
,ny
-cy
)==1)){
167 if(widl
>maxwid
) maxwid
=widl
;
177 //at this point *tmp is completed RUN CHRIS' ALGORITH TO CREATE *SOI and *SOIP
178 create_label_table();
180 // Remove temporary array
184 /** Given two points, tags all the computational boxes that the line segment
185 * specified by the two points
186 * goes through. param[in] (x1,y1) this is one point
187 * \param[in] (x2,y2) this is the other point.
188 * \param[in] wid this is the wall id bnds[2*wid] is the x index of the first
189 * vertex in the c-c direction. */
190 void container_2d::tag_walls(double x1
, double y1
, double x2
, double y2
, int wid
){
191 int cgrid
=0, cgridx
=0, cgridy
=0, fgrid
=0;
192 double slope
, slopec
, cx
=ax
+boxx
, cy
=ay
+boxy
, gridx
, gridy
;
195 double tmpx
=x1
, tmpy
=y1
;
196 x1
=x2
; y1
=y2
; x2
=tmpx
; y2
=tmpy
;
207 cy
=ay
+boxy
; cx
=ax
+boxx
;
214 }if(cx
==x2
&& x2
!=x1
&& cx
!=ax
+(boxx
*nx
)) fgrid
++;
225 slope
=((y2
-y1
)/(x2
-x1
));
226 if(slope
>0 && cy
==y2
&& cy
!=ay
+(boxy
*ny
)) fgrid
+=nx
;
228 for(int i
=cgrid
; i
<=fgrid
; i
++){
238 gridx
=ax
+((1+cgridx
)*boxx
);
239 gridy
=ay
+((1+cgridy
)*boxy
);
252 slopec
=((gridy
-y1
)/(gridx
-x1
));
255 x1
+=((1/slope
)*(gridy
-y1
));
259 } else if(slope
<slopec
){
261 y1
+=(slope
*(gridx
-x1
));
265 } else if(slope
==slopec
){
287 gridx
=ax
+((1+cgridx
)*boxx
);
288 gridy
=ay
+(cgridy
*boxy
);
301 slopec
=((gridy
-y1
)/(gridx
-x1
));
305 y1
+=(slope
*(gridx
-x1
));
308 } else if(slope
<slopec
){
311 x1
+=((1/slope
)*(gridy
-y1
));
314 } else if(slope
==slopec
){
335 /* A helper function for semi-circle-labelling. If crossproductz(x1,y1,particlex,particley)>0 then the particle is on the appropriate side of the wall to be tagged. */
336 int container_2d::crossproductz(double x1
, double y1
, double x2
, double y2
){
337 if(((x1
*y2
)-(x2
*y1
))>0) return 1;
341 /* Tags particles that are within a semicircle (on the appropriate side) of a boundary.
342 * \param[in] (x1,y1) the start point of the wall segment, arranged so that it
343 * is the first point reached in the counter-clockwise
345 * \param[in] (x2,y2) the end points of the wall segment. */
346 void container_2d::semi_circle_labelling(double x1
, double y1
, double x2
, double y2
, int bid
){
347 cout
<< " \n semi-circle-labelling\n bid=" << bid
<< "\n (x1,y1)(x2,y2)=(" << x1
<< "," << y1
348 << ")(" << x2
<< "," << y2
<< ") \n" << endl
;
349 voropp_loop_2d
l(*this);
350 double xmin
,xmax
,ymin
,ymax
, radius
=(dist(x1
,y1
,x2
,y2
)/2),dummy1
,dummy2
,midx
=(x1
+x2
)/2,
352 double cpx
,cpy
; //these stand for "current particle x" and "current particle y"
353 int box
; //this holds the current computational box that we're in.
354 printf("SCC %g %g %g %g\n",x1
,y1
,x2
,y2
);
356 // First we will initialize the voropp_loop_2d object to a rectangle
357 // containing all the points we are interested in plus some extraneous
358 // points. The larger the slope between (x1,y1) and (x2,y2) is, the
359 // more extraneous points we get- might change this later on.
365 ymax
=((y1
+y2
)/2)+radius
;
370 ymin
=((y1
+y2
)/2)-radius
;
386 // Now loop through all the particles in the boxes we found. Tagging
387 // the ones that are within radius of (midx,midy) and are on the
388 // appropriate side of the wall.
389 box
=l
.init(midx
,midy
,radius
, dummy1
,dummy2
);
391 for(int j
=0;j
<co
[box
];j
++){
394 cout
<< "\n now checking (x,y)=(" << cpx
<<"," <<cpy
<<")\n"<<endl
;
395 if(dist(midx
,midy
,cpx
,cpy
)<=radius
&&
396 crossproductz((x1
-x2
),(y1
-y2
),(cpx
-x2
),(cpy
-y2
))>0&&
397 (cpx
!=x1
||cpy
==y1
)&&(cpx
!=x2
||cpy
!=y2
)) {
398 if(tmpp
==tmpe
) add_temporary_label_memory();
402 printf("JKL %g %g\n",cpx
,cpy
);
403 cout
<< "WE ADDED ONE!" << endl
;
406 } while((box
=l
.inc(dummy1
,dummy2
))!=-1);
409 void container_2d::create_label_table() {
410 int ij
,q
,*pp
,tlab(0);
412 // Clear label counters
413 for(ij
=0;ij
<nxy
;ij
++) for(q
=0;q
<co
[ij
];q
++) nlab
[ij
][q
]=0;
415 // Increment label counters
416 for(pp
=tmp
;pp
<tmpp
;pp
+=3) {nlab
[*pp
][pp
[1]]++;tlab
++;}
418 // Check for case of no labels at all (which may be common)
420 #if VOROPP_VERBOSE >=2
421 fputs("No labels needed",stderr
);
426 // If there was already a table from a previous call, remove it
427 if(soi
!=NULL
) delete [] soi
;
429 // Allocate the label array, and set up pointers from each particle
430 // to the corresponding location
431 pp
=soi
=new int[tlab
];
432 for(ij
=0;ij
<nxy
;ij
++) for(q
=0;q
<co
[ij
];pp
+=nlab
[ij
][q
++]) plab
[ij
][q
]=pp
;
434 // Fill in the label entries
435 for(pp
=tmp
;pp
<tmpp
;pp
+=3) *(plab
[*pp
][pp
[1]]++)=pp
[2];
437 // Reset the label pointers
439 for(ij
=0;ij
<nxy
;ij
++) for(q
=0;q
<co
[ij
];pp
+=nlab
[ij
][q
++]) plab
[ij
][q
]=pp
;
442 /** Draws the boundaries. (Note: this currently assumes that each boundary loop
443 * is a continuous block in the bnds array, which will be true for the import
444 * function. However, it may not be true in other cases, in which case this
445 * routine would have to be extended.) */
446 void container_2d::draw_boundary(FILE *fp
) {
449 for(i
=0;i
<noofbnds
;i
++) {
450 fprintf(fp
,"%d %g %g\n",i
,bnds
[2*i
],bnds
[2*i
+1]);
452 // If a loop is detected, than complete the loop in the output file
453 // and insert a newline
454 if(edb
[i
]<i
) fprintf(fp
,"%g %g\n\n",bnds
[2*edb
[i
]],bnds
[2*edb
[i
]+1]);
458 /** Increases the size of the temporary label memory. */
459 void container_2d::add_temporary_label_memory() {
462 if(size
>3*max_temp_label_size
)
463 voropp_fatal_error("Absolute temporary label memory allocation exceeded",VOROPP_MEMORY_ERROR
);
464 #if VOROPP_VERBOSE >=3
465 fprintf(stderr
,"Temporary label memory in region scaled up to %d\n",size
);
467 int *ntmp(new int[size
]),*tp(tmp
);tmpp
=ntmp
;
468 while(tp
<tmpe
) *(tmpp
++)=*(tp
++);
470 tmp
=ntmp
;tmpe
=tmp
+size
;
473 /** Increases the memory allocation for the boundary points. */
474 void container_2d::add_boundary_memory() {
475 int i
,size(bnds_size
<<1);
476 if(size
>max_bnds_size
)
477 voropp_fatal_error("Absolute bounds memory allocation exceeded",VOROPP_MEMORY_ERROR
);
478 #if VOROPP_VERBOSE >=3
479 fprintf(stderr
,"Bounds memory scaled up to %d\n",size
);
482 // Reallocate the boundary vertex information
483 double *nbnds(new double[2*size
]);
484 for(i
=0;i
<2*noofbnds
;i
++) nbnds
[i
]=bnds
[i
];
485 delete [] nbnds
;bnds
=nbnds
;
487 // Reallocate the edge information
488 int *nedb(new int[2*size
]);
489 for(i
=0;i
<noofbnds
;i
++) nedb
[i
]=edb
[i
];
490 delete [] edb
;edb
=nedb
;
492 /** given two particles, a generator and a potential cutting particle, this returns true iff the cutting
493 particle and the generator are on the same side of all relevant walls. **/
495 bool container_2d::OKCuttingParticle(double gx
, double gy
, int gbox
, int gindex
, double cx
, double cy
, int cbox
, int cindex
, bool boundary
, int bid
){
497 double widx1
, widy1
, widx2
, widy2
;
501 int lwid
=edb
[2*bid
+1];
502 double nx
=bnds
[2*nwid
]-gx
; double ny
=bnds
[2*nwid
+1]-gy
;
503 double lx
=bnds
[2*lwid
]-gx
; double ly
=bnds
[2*lwid
+1]-gy
;
504 double nxp
=-ny
, nyp
=nx
, lxp
=ly
, lyp
=-lx
;
508 if(crossproductz(lx
,ly
,nx
,ny
)==1){
509 nxp
*=-1; nyp
*=-1; lxp
*=-1; lyp
*=-1;
510 if((((lxp
*(cx
-gx
))+(lyp
*(cy
-gy
)))>0) && (((nxp
*(cx
-gx
))+(nyp
*(cy
-gy
)))>0)){
515 if((((lxp
*(cx
-gx
))+(lyp
*(cy
-gy
)))<0) || (((nxp
*(cx
-gx
))+(nyp
*(cy
-gy
)))<0)){
520 nxp=-ny; nyp=nx; lxp=ly; lyp=-lx;
521 if(crossproductz(lx,ly,nx,ny)==1){
523 if((((lxp*(cx-gx))+(lyp*(cy-gy)))<tolerance) || (((nxp*(cx-gx))+(nyp*(cy-gy)))<tolerance)){
527 nxp*=-1; nyp*=-1; lxp*=-1; lyp*=-1;
529 if((((lxp*(cx-gx))+(lyp*(cy-gy)))>tolerance) && (((nxp*(cx-gx))+(nyp*(cy-gy)))>tolerance)){
540 for(int i
=0;i
<(signed int)nlab
[cbox
][cindex
];i
++){
541 cwid
=plab
[cbox
][cindex
][i
];
543 widy1
=bnds
[2*cwid
+1];
546 widy2
=bnds
[2*nwid
+1];
547 if(((cx
==widx1
&& cy
==widy1
) || (cx
==widx2
&& cy
==widy2
)) || (boundary
&& ((gx
==widx1
&& gy
==widy1
) || (gx
==widx2
&& gy
==widy2
)))) continue;
548 if(crossproductz(gx
-widx1
,gy
-widy1
,widx2
-widx1
,widy2
-widy1
)!=
549 crossproductz(cx
-widx1
,cy
-widy1
,widx2
-widx1
,widy2
-widy1
)) return false;
554 /** Increase memory for a particular region.
555 * \param[in] i the index of the region to reallocate. */
556 void container_2d::add_particle_memory(int i
) {
559 if(mem
[i
]>max_particle_memory
)
560 voropp_fatal_error("Absolute maximum particle memory allocation exceeded",VOROPP_MEMORY_ERROR
);
561 #if VOROPP_VERBOSE >=3
562 fprintf(stderr
,"Particle memory in region %d scaled up to %d\n",i
,mem
[i
]);
565 // Create new arrays and copy across the data
566 int *idp(new int[mem
[i
]]);
567 int *bndptsp(new int[mem
[i
]]);
568 for(l
=0;l
<co
[i
];l
++) {
572 double *pp(new double[2*mem
[i
]]);
573 for(l
=0;l
<2*co
[i
];l
++) pp
[l
]=p
[i
][l
];
574 unsigned int *nlabp(new unsigned int[mem
[i
]]);
575 for(l
=0;l
<co
[i
];l
++) nlabp
[l
]=nlab
[i
][l
];
576 int **plabp(new int*[mem
[i
]]);
577 for(l
=0;l
<co
[i
];l
++) plabp
[l
]=plab
[i
][l
];
579 // Delete the original arrays and update the pointers
580 delete [] id
[i
];id
[i
]=idp
;
581 delete [] bndpts
[i
]; bndpts
[i
]=bndptsp
;
582 delete [] p
[i
];p
[i
]=pp
;
583 delete [] nlab
[i
];nlab
[i
]=nlabp
;
584 delete [] plab
[i
];plab
[i
]=plabp
;
587 void container_2d::add_edb_memory(int i
){
588 int *edbp(new int[50*(i
+1)]);
589 for(int l
=0;l
<(50*i
);l
++){
592 delete [] edb
; edb
=edbp
;
594 /** Imports a list of particles from an input stream.
595 * \param[in] fp a file handle to read from. */
596 void container_2d::import(FILE *fp
) {
598 bool boundary(false);
600 char *buf(new char[512]);
602 while(fgets(buf
,512,fp
)!=NULL
) {
603 if(strcmp(buf
,"#Start\n")==0||strcmp(buf
,"# Start\n")==0) {
605 // Check that two consecutive start tokens haven't been
607 if(boundary
) voropp_fatal_error("File import error - two start tokens found",VOROPP_FILE_ERROR
);
608 // Remember this position in the boundary array to
609 // connect the end of the loop
613 } else if(strcmp(buf
,"#End\n")==0||strcmp(buf
,"# End\n")==0) {
615 // Check that two consecutive end tokens haven't been
617 if(!boundary
) voropp_fatal_error("File import error - two end tokens found",VOROPP_FILE_ERROR
);
618 // Assuming that at least one point was read, set the edge
619 // to connect back to the start point
620 edb
[2*sm
+1]=noofbnds
-1;
621 edb
[2*(noofbnds
-1)]=sm
;
625 // Try and read three entries from the line
626 if(sscanf(buf
,"%d %lg %lg",&i
,&x
,&y
)!=3) voropp_fatal_error("File import error #1",VOROPP_FILE_ERROR
);
627 if(!boundary
) put(i
,x
,y
, -1);
630 // Unless this is the start of a boundary loop,
631 // connect the previous vertex to this one
633 add_edb_memory(noofbnds
/25);
636 edb
[(noofbnds
-1)*2]=noofbnds
;
637 edb
[(noofbnds
*2)+1]=noofbnds
-1;
640 bnds
[2*(noofbnds
++)+1]=y
;
645 if(!feof(fp
)) voropp_fatal_error("File import error #2",VOROPP_FILE_ERROR
);
649 /** Clears a container of particles. */
650 void container_2d::clear() {
651 for(int* cop
=co
;cop
<co
+nxy
;cop
++) *cop
=0;
654 /** Dumps all the particle positions and IDs to a file.
655 * \param[in] fp the file handle to write to. */
656 void container_2d::draw_particles(FILE *fp
) {
658 for(ij
=0;ij
<nxy
;ij
++) for(q
=0;q
<co
[ij
];q
++)
659 fprintf(fp
,"%d %g %g\n",id
[ij
][q
],p
[ij
][2*q
],p
[ij
][2*q
+1]);
662 /** Dumps all the particle positions in POV-Ray format.
663 * \param[in] fp the file handle to write to. */
664 void container_2d::draw_particles_pov(FILE *fp
) {
666 for(ij
=0;ij
<nxy
;ij
++) for(q
=0;q
<co
[ij
];q
++)
667 fprintf(fp
,"// id %d\nsphere{<%g,%g,0>,s\n",id
[ij
][q
],p
[ij
][2*q
],p
[ij
][2*q
+1]);
670 /** Computes the Voronoi cells for all particles and saves the output in
672 * \param[in] fp a file handle to write to. */
673 void container_2d::draw_cells_gnuplot(FILE *fp
) {
677 for(j
=0;j
<ny
;j
++) for(i
=0;i
<nx
;i
++,ij
++) for(q
=0;q
<co
[ij
];q
++) {
678 x
=p
[ij
][2*q
];y
=p
[ij
][2*q
+1];
679 if(compute_cell_sphere(c
,i
,j
,ij
,q
,x
,y
)) c
.draw_gnuplot(x
,y
,fp
);
683 /** Computes the Voronoi cells for all particles within a rectangular box, and
684 * saves the output in POV-Ray format.
685 * \param[in] fp a file handle to write to. */
686 void container_2d::draw_cells_pov(FILE *fp
) {
690 for(j
=0;j
<ny
;j
++) for(i
=0;i
<nx
;i
++,ij
++) for(q
=0;q
<co
[ij
];q
++) {
691 x
=p
[ij
][2*q
];y
=p
[ij
][2*q
+1];
692 if(compute_cell_sphere(c
,i
,j
,ij
,q
,x
,y
)) {
693 fprintf(fp
,"// cell %d\n",id
[ij
][q
]);
694 c
.draw_pov(x
,y
,0,fp
);
699 /** Computes the Voronoi cells for all particles in the container, and for each
700 * cell, outputs a line containing custom information about the cell structure.
701 * The output format is specified using an input string with control sequences
702 * similar to the standard C printf() routine.
703 * \param[in] format the format of the output lines, using control sequences to
704 * denote the different cell statistics.
705 * \param[in] fp a file handle to write to. */
706 void container_2d::print_custom(const char *format
,FILE *fp
) {
710 for(j
=0;j
<ny
;j
++) for(i
=0;i
<nx
;i
++,ij
++) for(q
=0;q
<co
[ij
];q
++) {
711 x
=p
[ij
][2*q
];y
=p
[ij
][2*q
+1];
712 if(compute_cell_sphere(c
,i
,j
,ij
,q
,x
,y
)) c
.output_custom(format
,id
[ij
][q
],x
,y
,default_radius
,fp
);
716 /** Initializes a voronoicell_2d class to fill the entire container.
717 * \param[in] c a reference to a voronoicell_2d class.
718 * \param[in] (x,y) the position of the particle that . */
720 bool container_2d::initialize_voronoicell(voronoicell_2d
&c
,double x
,double y
) {
723 if(xperiodic
) x1
=-(x2
=0.5*(bx
-ax
));else {x1
=ax
-x
;x2
=bx
-x
;}
724 if(yperiodic
) y1
=-(y2
=0.5*(by
-ay
));else {y1
=ay
-y
;y2
=by
-y
;}
730 bool container_2d::initialize_voronoicell_nonconvex(voronoicell_2d
&c
, double x
, double y
, int bid
){
731 double* bnds_loc
=new double[noofbnds
*2];
732 int fbid
=bid
, cntbndno
=1;
733 bnds_loc
[0]=0; bnds_loc
[1]=0;
737 if(bid
==(noofbnds
)) bid
=0;
738 bnds_loc
[cntbndno
*2]=bnds
[bid
*2]-x
;
739 bnds_loc
[cntbndno
*2+1]=bnds
[bid
*2+1]-y
;
743 c
.init_nonconvex(bnds_loc
, cntbndno
);
751 void container_2d::container_projection(double x
, double y
, double &ccx
, double &ccy
, double &nx
, double &ny
){
752 double ccs
, slope
, distx
, disty
;
754 if((ccx
-x
)==0 && (ccy
>y
)){
758 }else if((ccx
-x
)==0 && (ccy
<y
)){
763 ccs
= (ccy
-y
)/(ccx
-x
);
764 if((ccs
==0) && (ccx
>x
)){
768 }else if((ccs
==0) && (ccx
<x
)){
859 bool container_2d::initialize_voronoicell_boundary(voronoicell_2d
&c
, double x
, double y
, int bid
){
860 double* bnds_loc
=new double[14];
861 double ccx
, ccy
, cx
, cy
, nx
, ny
, dum1
, dum2
;
862 int noofbndsloc
, ccwid
, cwid
;
865 ccx
=bnds
[2*ccwid
]; ccy
=bnds
[2*ccwid
+1];
866 cx
=bnds
[2*cwid
]; cy
=bnds
[2*cwid
+1];
867 //compute the counter-clockwise and clockwise projection;
868 container_projection(x
,y
,ccx
,ccy
, nx
, ny
);
869 container_projection(x
,y
,cx
,cy
, dum1
, dum2
);
872 //construct bnds_loc;
873 bnds_loc
[0]=0; bnds_loc
[1]=0;
874 bnds_loc
[2]=ccx
-x
; bnds_loc
[3]=ccy
-y
;
877 if(nx
==ax
&& ny
==ay
){
878 if(cx
==ax
&& (fabs(cy
-ay
)<fabs(ccy
-ay
))){
879 bnds_loc
[2*noofbndsloc
]=cx
-x
;
880 bnds_loc
[2*noofbndsloc
+1]=cy
-y
;
882 c
.init_nonconvex(bnds_loc
,noofbndsloc
);
885 bnds_loc
[2*noofbndsloc
]=nx
-x
;
886 bnds_loc
[2*noofbndsloc
+1]=ny
-y
;
888 ccx
=ax
; ccy
=ay
; nx
=bx
; ny
=ay
;
891 }else if(nx
==bx
&& ny
==ay
){
892 if(cy
==ay
&& (fabs(cx
-bx
)<fabs(ccx
-bx
))){
893 bnds_loc
[2*noofbndsloc
]=cx
-x
;
894 bnds_loc
[2*noofbndsloc
+1]=cy
-y
;
896 c
.init_nonconvex(bnds_loc
,noofbndsloc
);
899 bnds_loc
[2*noofbndsloc
]=nx
-x
;
900 bnds_loc
[2*noofbndsloc
+1]=ny
-y
;
902 ccx
=bx
; ccy
=ay
; nx
=bx
; ny
=by
;
905 }else if(nx
==bx
&& ny
==by
){
906 if(cx
==bx
&& (fabs(cy
-by
)<fabs(ccy
-by
))){
907 bnds_loc
[2*noofbndsloc
]=cx
-x
;
908 bnds_loc
[2*noofbndsloc
+1]=cy
-y
;
910 c
.init_nonconvex(bnds_loc
,noofbndsloc
);
913 bnds_loc
[2*noofbndsloc
]=nx
-x
;
914 bnds_loc
[2*noofbndsloc
+1]=ny
-y
;
916 nx
=ax
; ny
=by
; ccx
=bx
; ccy
=by
;
919 }else if(nx
==ax
&& ny
==by
){
920 if(cy
==by
&& (fabs(cx
-ax
)<fabs(ccx
-ax
))){
921 bnds_loc
[2*noofbndsloc
]=cx
-x
;
922 bnds_loc
[2*noofbndsloc
+1]=cy
-y
;
924 c
.init_nonconvex(bnds_loc
,noofbndsloc
);
927 bnds_loc
[2*noofbndsloc
]=nx
-x
;
928 bnds_loc
[2*noofbndsloc
+1]=ny
-y
;
930 nx
=ax
; ny
=ay
; ccx
=ax
; ccy
=by
;
933 cout
<< "major error in init_boundary" << endl
;
946 /** Computes all Voronoi cells and sums their areas.
947 * \return The computed area. */
948 double container_2d::sum_cell_areas() {
952 for(j
=0;j
<ny
;j
++) for(i
=0;i
<nx
;i
++,ij
++) for(q
=0;q
<co
[ij
];q
++) {
953 x
=p
[ij
][2*q
];y
=p
[ij
][2*q
+1];
954 if(compute_cell_sphere(c
,i
,j
,ij
,q
,x
,y
)) sum
+=c
.cell_area();
959 /** Computes all of the Voronoi cells in the container, but does nothing
960 * with the output. It is useful for measuring the pure computation time
961 * of the Voronoi algorithm, without any additional calculations such as
962 * volume evaluation or cell output. */
963 void container_2d::compute_all_cells() {
966 for(i
=0;i
<nx
;i
++,ij
++){
967 for(q
=0;q
<co
[ij
];q
++){
969 cout
<< " " << i
<< " " << j
<< " " << q
<< " " << endl
;
970 compute_cell_sphere(c
,i
,j
,ij
,q
);
976 //Reports the state of bndpts, plab, nlab, wid, and edb after setup() has been run.
977 void container_2d::debug_output(){
980 cout
<< "problem points \n";
981 for(int i
=0; i
<nxy
; i
++){
982 for(int j
=0; j
<co
[i
]; j
++){
984 if(lid
!=-1 && probpts
[lid
]) cout
<< lid
<< ", (x,y)=(" << p
[i
][2*j
] << "," << p
[i
][2*j
+1] << ") \n" << endl
;
988 cout
<< "semi_circle_labelling \n";
989 for(int i
=0; i
<nxy
; i
++){
990 for(int j
=0; j
<co
[i
]; j
++){
991 cout
<< " \t computational box= " << i
<< "\n \t \t paricle_no= " << id
[i
][j
] << "(x,y)=(" << p
[i
][2*j
] << "," << p
[i
][2*j
+1] << ")" << "\n \t \t \t wall_ids=" << endl
;
992 for(int q
=0;q
<(signed int)nlab
[i
][j
];q
++){
993 cout
<< "\n \t \t \t \t " << plab
[i
][j
][q
] << " " << endl
;
998 cout
<< "wall_tags \n";
999 for(int i
=0; i
<nxy
; i
++){
1000 cout
<< " \t computational box # " << i
<< " wall tags \n ";
1001 for(int j
=1; j
<wid
[i
][0] ; j
++){
1002 cout
<< "\t \t" << wid
[i
][j
] << " \n";
1006 for (int i
=0; i
<noofbnds
; i
++){
1007 cout
<< "\n wid=" << i
<< "\n lwid=" << edb
[2*i
+1] << "\n nwid=" << edb
[2*i
] << endl
;
1011 void container_2d::initial_cut_nonconvex(voronoicell_2d
&c
,double x
, double y
, int bid
){
1013 double widx1
, widy1
, widx2
, widy2
, rs
;
1014 wid1
=edb
[2*bid
]; wid2
=edb
[2*bid
+1];
1015 widx1
=bnds
[2*wid1
]-x
; widy1
=bnds
[2*wid1
+1]-y
;
1016 widx2
=bnds
[2*wid2
]-x
; widy2
=bnds
[2*wid2
+1]-y
;
1017 c
.initialize_regions(widx1
, widy1
, widx2
, widy2
, extpts
[bid
]);
1018 rs
=widx1
*widx1
+widy1
*widy1
;
1019 c
.halfplane(widx1
,widy1
,rs
, -widy2
, widx2
);
1020 rs
=widx2
*widx2
+widy2
*widy2
;
1021 c
.halfplane(widx2
,widy2
,rs
, widy1
, -widx1
);
1023 void container_2d::initial_cut(voronoicell_2d
&c
,double x
, double y
, int bid
){
1025 double widx1
, widy1
, widx2
, widy2
, rs
;
1026 wid1
=edb
[2*bid
]; wid2
=edb
[2*bid
+1];
1027 widx1
=bnds
[2*wid1
]-x
; widy1
=bnds
[2*wid1
+1]-y
;
1028 widx2
=bnds
[2*wid2
]-x
; widy2
=bnds
[2*wid2
+1]-y
;
1029 rs
=widx1
*widx1
+widy1
*widy1
;
1030 c
.plane(widx1
,widy1
,rs
);
1031 rs
=widx2
*widx2
+widy2
*widy2
;
1032 c
.plane(widx2
,widy2
,rs
);
1035 /** This routine computes the Voronoi cell for a give particle, by successively
1036 * testing over particles within larger and larger concentric circles. This
1037 * routine is simple and fast, although it may not work well for anisotropic
1038 * arrangements of particles.
1039 * \param[in,out] c a reference to a voronoicell object.
1040 * \param[in] (i,j) the coordinates of the block that the test particle is
1042 * \param[in] ij the index of the block that the test particle is in, set to
1044 * \param[in] s the index of the particle within the test block.
1045 * \param[in] (x,y) the coordinates of the particle.
1046 * \return False if the Voronoi cell was completely removed during the
1047 * computation and has zero volume, true otherwise. */
1048 bool container_2d::compute_cell_sphere(voronoicell_2d
&c
,int i
,int j
,int ij
,int s
,double x
,double y
) {
1049 // This length scale determines how large the spherical shells should
1050 // be, and it should be set to approximately the particle diameter
1051 const double length_scale
=0.5*sqrt((bx
-ax
)*(by
-ay
)/(nx
*ny
));
1052 bool problem_point
=false, boundary
=false;
1053 double x1
,y1
,qx
,qy
,lr
=0,lrs
=0,ur
,urs
,rs
,wx1
,wy1
,wx2
,wy2
;
1054 int q
,t
,bid
, widc
, widc2
;
1055 voropp_loop_2d
l(*this);
1057 //Check if the current point is a problem point, if it is we will need to use plane-nonconvex, and init_nonconvex
1059 if(bid
!=-1 && probpts
[bid
]){
1060 if(!initialize_voronoicell_boundary(c
,x
,y
,bid
)) return false;
1063 initial_cut_nonconvex(c
,x
,y
,bid
);
1066 if(!initialize_voronoicell_boundary(c
,x
,y
,bid
)) return false;
1067 initial_cut(c
,x
,y
,bid
);
1071 if(!initialize_voronoicell(c
,x
,y
)) return false;
1073 // Now the cell is cut by testing neighboring particles in concentric
1074 // shells. Once the test shell becomes twice as large as the Voronoi
1075 // cell we can stop testing.
1076 while(lrs
<c
.max_radius_squared()) {
1077 ur
=lr
+0.5*length_scale
;urs
=ur
*ur
;
1078 t
=l
.init(x
,y
,ur
,qx
,qy
);
1080 //CUT BY ALL WALLS PASSING THROUGH THE COMPUTATIONAL BOX HERE, USE WID
1081 for(int b
=1;b
<wid
[t
][0];b
++){
1083 if(widc
>(noofbnds
-1)) continue;
1084 wx1
=bnds
[2*widc
]-x
; wy1
=bnds
[2*widc
+1]-y
;
1087 wx2
=bnds
[2*widc2
]-x
; wy2
=bnds
[2*widc2
+1]-y
;
1088 if((wx1
==0 && wy1
==0) || (wx2
==0 && wy2
==0)) continue;
1089 c
.wallcut(wx1
,wy1
,wx2
,wy2
);
1091 for(q
=0;q
<co
[t
];q
++) {
1093 //HERE CHECK IF THE CUTTING PARTICLE IS ON THE WRONG SIDE OF ANY WALL USING SOI
1094 x1
=p
[t
][2*q
]+qx
;y1
=p
[t
][2*q
+1]+qy
;//qx,qy??
1096 if(!(x1
==x
&& y1
==y
) && OKCuttingParticle(x
,y
,ij
,s
,x1
,y1
,t
,q
, boundary
, bid
)){
1099 if(lrs
-tolerance
<rs
&&rs
<urs
&&(q
!=s
||ij
!=t
)) {
1101 if(!c
.plane_nonconvex(x1
,y1
,rs
)) return false;
1103 if(!c
.plane(x1
,y1
,rs
)) return false;
1109 } while((t
=l
.inc(qx
,qy
))!=-1);//loops through boxes in the shell
1113 initial_cut_nonconvex(c
,x
,y
,bid
);
1115 initial_cut(c
,x
,y
,bid
);
1120 /** Creates a voropp_loop_2d object, by setting the necessary constants about the
1121 * container geometry from a pointer to the current container class.
1122 * \param[in] con a reference to the associated container class. */
1123 voropp_loop_2d::voropp_loop_2d(container_2d
&con
) : boxx(con
.bx
-con
.ax
), boxy(con
.by
-con
.ay
),
1124 xsp(con
.xsp
),ysp(con
.ysp
),
1125 ax(con
.ax
),ay(con
.ay
),nx(con
.nx
),ny(con
.ny
),nxy(con
.nxy
),
1126 xperiodic(con
.xperiodic
),yperiodic(con
.yperiodic
) {}
1128 /** Initializes a voropp_loop_2d object, by finding all blocks which are within a
1129 * given sphere. It calculates the index of the first block that needs to be
1130 * tested and sets the periodic displacement vector accordingly.
1131 * \param[in] (vx,vy) the position vector of the center of the sphere.
1132 * \param[in] r the radius of the sphere.
1133 * \param[out] (px,py) the periodic displacement vector for the first block to
1135 * \return The index of the first block to be tested. */
1136 int voropp_loop_2d::init(double vx
,double vy
,double r
,double &px
,double &py
) {
1137 ai
=step_int((vx
-ax
-r
)*xsp
);
1138 bi
=step_int((vx
-ax
+r
)*xsp
);
1140 if(ai
<0) {ai
=0;if(bi
<0) bi
=0;}
1141 if(bi
>=nx
) {bi
=nx
-1;if(ai
>=nx
) ai
=nx
-1;}
1143 aj
=step_int((vy
-ay
-r
)*ysp
);
1144 bj
=step_int((vy
-ay
+r
)*ysp
);
1146 if(aj
<0) {aj
=0;if(bj
<0) bj
=0;}
1147 if(bj
>=ny
) {bj
=ny
-1;if(aj
>=ny
) aj
=ny
-1;}
1150 aip
=ip
=step_mod(i
,nx
);apx
=px
=step_div(i
,nx
)*boxx
;
1151 ajp
=jp
=step_mod(j
,ny
);apy
=py
=step_div(j
,ny
)*boxy
;
1152 inc1
=aip
-step_mod(bi
,nx
)+nx
;
1157 /** Initializes a voropp_loop_2d object, by finding all blocks which overlap a given
1158 * rectangular box. It calculates the index of the first block that needs to be
1159 * tested and sets the periodic displacement vector (px,py,pz) accordingly.
1160 * \param[in] (xmin,xmax) the minimum and maximum x coordinates of the box.
1161 * \param[in] (ymin,ymax) the minimum and maximum y coordinates of the box.
1162 * \param[out] (px,py) the periodic displacement vector for the first block
1164 * \return The index of the first block to be tested. */
1165 int voropp_loop_2d::init(double xmin
,double xmax
,double ymin
,double ymax
,double &px
,double &py
) {
1166 ai
=step_int((xmin
-ax
)*xsp
);
1167 bi
=step_int((xmax
-ax
)*xsp
);
1169 if(ai
<0) {ai
=0;if(bi
<0) bi
=0;}
1170 if(bi
>=nx
) {bi
=nx
-1;if(ai
>=nx
) ai
=nx
-1;}
1172 aj
=step_int((ymin
-ay
)*ysp
);
1173 bj
=step_int((ymax
-ay
)*ysp
);
1175 if(aj
<0) {aj
=0;if(bj
<0) bj
=0;}
1176 if(bj
>=ny
) {bj
=ny
-1;if(aj
>=ny
) aj
=ny
-1;}
1179 aip
=ip
=step_mod(i
,nx
);apx
=px
=step_div(i
,nx
)*boxx
;
1180 ajp
=jp
=step_mod(j
,ny
);apy
=py
=step_div(j
,ny
)*boxy
;
1181 inc1
=aip
-step_mod(bi
,nx
)+nx
;
1186 /** Returns the next block to be tested in a loop, and updates the periodicity
1187 * vector if necessary.
1188 * \param[in,out] (px,py) the current block on entering the function, which is
1189 * updated to the next block on exiting the function. */
1190 int voropp_loop_2d::inc(double &px
,double &py
) {
1193 if(ip
<nx
-1) {ip
++;s
++;} else {ip
=0;s
+=1-nx
;px
+=boxx
;}
1196 i
=ai
;ip
=aip
;px
=apx
;j
++;
1197 if(jp
<ny
-1) {jp
++;s
+=inc1
;} else {jp
=0;s
+=inc1
-nxy
;py
+=boxy
;}