#include "v_network.hh" /** Initializes the Voronoi network object. The geometry is set up to match a * corresponding container class, and memory is allocated for the network. * \param[in] c a reference to a container or container_poly class. */ template voronoi_network::voronoi_network(c_class &c,double net_tol_) : bx(c.bx), bxy(c.bxy), by(c.by), bxz(c.bxz), byz(c.byz), bz(c.bz), nx(c.nx), ny(c.ny), nz(c.nz), nxyz(nx*ny*nz), xsp(nx/bx), ysp(ny/by), zsp(nz/bz), net_tol(net_tol_) { int l; // Allocate memory for vertex structure pts=new double*[nxyz]; idmem=new int*[nxyz]; ptsc=new int[nxyz]; ptsmem=new int[nxyz]; for(l=0;lmax_network_vertex_memory) voro_fatal_error("Container vertex maximum memory allocation exceeded",VOROPP_MEMORY_ERROR); // Allocate new arrays double *npts(new double[4*ptsmem[l]]); int *nidmem(new int[ptsmem[l]]); // Copy the contents of the old arrays into the new ones for(int i=0;i<4*ptsc[l];i++) npts[i]=pts[l][i]; for(int i=0;imax_vertex_order) voro_fatal_error("Particular vertex maximum memory allocation exceeded",VOROPP_MEMORY_ERROR); // Allocate new arrays int *ned(new int[2*numem[l]]); int *nne(ned+numem[l]); block *nraded(new block[numem[l]]); unsigned int *npered(new unsigned int[numem[l]]); // Copy the contents of the old arrays into the new ones for(int i=0;i %d",l,ed[l][q]); raded[l][q].print(fp); // Compute and print the length of the edge ptsp=pts[reg[ed[l][q]]];j=4*regp[ed[l][q]]; x2=ptsp[j]+ai*bx+aj*bxy+ak*bxz-x; y2=ptsp[j+1]+aj*by+ak*byz-y; z2=ptsp[j+2]+ak*bz-z; fprintf(fp," %d %d %d %g\n",ai,aj,ak,sqrt(x2*x2+y2*y2+z2*z2)); } } } // Converts three periodic image displacements into a single unsigned integer. // \param[in] i the periodic image in the x direction. // \param[in] j the periodic image in the y direction. // \param[in] k the periodic image in the z direction. // \return The packed integer. */ inline unsigned int voronoi_network::pack_periodicity(int i,int j,int k) { unsigned int pa=((unsigned int) (127+i)); pa<<=8;pa+=((unsigned int) (127+j)); pa<<=8;pa+=((unsigned int) (127+k)); return pa; } /** Unpacks an unsigned integer into three periodic image displacements. * \param[in] pa the packed integer. // \param[out] i the periodic image in the x direction. // \param[out] j the periodic image in the y direction. // \param[out] k the periodic image in the z direction. */ inline void voronoi_network::unpack_periodicity(unsigned int pa,int &i,int &j,int &k) { i=((signed int) (pa>>16))-127; j=((signed int) ((pa>>8)&255))-127; k=((signed int) (pa&255))-127; } /** Adds a Voronoi cell to the network structure. The routine first checks all * of the Voronoi cell vertices and merges them with existing ones where * possible. Edges are then added to the structure. * \param[in] c a reference to a Voronoi cell. * \param[in] (x,y,z) the position of the Voronoi cell. * \param[in] idn the ID number of the particle associated with the cell. */ template void voronoi_network::add_to_network_internal(v_cell &c,int idn,double x,double y,double z,double rad,int *cmap) { int i,j,k,ijk,l,q,ai,aj,ak,*vmp(cmap); double gx,gy,vx,vy,vz,crad,*cp(c.pts); // Loop over the vertices of the Voronoi cell for(l=0;lcrad) pts[ijk][4*q+3]=crad; } else { k=step_int(vz*zsp);if(k<0||k>=nz) {ak=step_div(k,nz);vx-=bxz*ak;vy-=byz*ak;vz-=bz*ak;k-=ak*nz;} else ak=0; j=step_int(gy*ysp);if(j<0||j>=ny) {aj=step_div(j,ny);vx-=bxy*aj;vy-=by*aj;j-=aj*ny;} else aj=0; i=step_int(gx*xsp);if(i<0||i>=nx) {ai=step_div(i,nx);vx-=bx*ai;i-=ai*nx;} else ai=0; vmp[1]=ai;vmp[2]=aj;vmp[3]=ak; ijk=i+nx*(j+ny*k); if(edc==edmem) add_edge_network_memory(); if(ptsc[ijk]==ptsmem[ijk]) add_network_memory(ijk); reg[edc]=ijk;regp[edc]=ptsc[ijk]; pts[ijk][4*ptsc[ijk]]=vx; pts[ijk][4*ptsc[ijk]+1]=vy; pts[ijk][4*ptsc[ijk]+2]=vz; pts[ijk][4*ptsc[ijk]+3]=crad; idmem[ijk][ptsc[ijk]++]=edc; *vmp=edc++; } // Add the neighbor information to this vertex add_neighbor(*vmp,idn); } add_edges_to_network(c,x,y,z,rad,cmap); } /** Adds a neighboring particle ID to a vertex in the Voronoi network, first * checking that the ID is not already recorded. * \param[in] k the Voronoi vertex. * \param[in] idn the particle ID number. */ inline void voronoi_network::add_neighbor(int k,int idn) { for(int i=0;i void voronoi_network::add_edges_to_network(v_cell &c,double x,double y,double z,double rad,int *cmap) { int i,j,ai,aj,ak,bi,bj,bk,k,l,q,*vmp;unsigned int cper; double vx,vy,vz,wx,wy,wz,dx,dy,dz,dis;double *pp; for(l=0;l1) dis=1; wx=vx-x+dis*dx;wy=vy-y+dis*dy;wz=vz-z+dis*dz; int nat=not_already_there(k,j,cper); if(nat==nu[k]) { if(nu[k]==numem[k]) add_particular_vertex_memory(k); ed[k][nu[k]]=j; raded[k][nu[k]].first(sqrt(wx*wx+wy*wy+wz*wz)-rad,dis); pered[k][nu[k]++]=cper; } else { raded[k][nat].add(sqrt(wx*wx+wy*wy+wz*wz)-rad,dis); } } } } template void voronoi_network::add_to_network_rectangular_internal(v_cell &c,int idn,double x,double y,double z,double rad,int *cmap) { int i,j,k,ijk,l,q,ai,aj,ak,*vmp(cmap); double vx,vy,vz,crad,*cp(c.pts); for(l=0;lcrad) pts[ijk][4*q+3]=crad; } else { k=step_int(vz*zsp); if(k<0||k>=nz) { ak=step_div(k,nz); vz-=ak*bz;vy-=ak*byz;vx-=ak*bxz;k-=ak*nz; } else ak=0; j=step_int(vy*ysp); if(j<0||j>=ny) { aj=step_div(j,ny); vy-=aj*by;vx-=aj*bxy;j-=aj*ny; } else aj=0; i=step_int(vx*xsp); if(i<0||i>=nx) { ai=step_div(i,nx); vx-=ai*bx;i-=ai*nx; } else ai=0; vmp[1]=ai; vmp[2]=aj; vmp[3]=ak; ijk=i+nx*(j+ny*k); if(edc==edmem) add_edge_network_memory(); if(ptsc[ijk]==ptsmem[ijk]) add_network_memory(ijk); reg[edc]=ijk;regp[edc]=ptsc[ijk]; pts[ijk][4*ptsc[ijk]]=vx; pts[ijk][4*ptsc[ijk]+1]=vy; pts[ijk][4*ptsc[ijk]+2]=vz; pts[ijk][4*ptsc[ijk]+3]=crad; idmem[ijk][ptsc[ijk]++]=edc; *vmp=edc++; } add_neighbor(*vmp,idn); } add_edges_to_network(c,x,y,z,rad,cmap); } int voronoi_network::not_already_there(int k,int j,unsigned int cper) { for(int i=0;i=nz) { ck=step_div(k,nz); z-=ck*bz;y-=ck*byz;x-=ck*bxz;k-=ck*nz; } else ck=0; int j=step_int(y*ysp); if(j<0||j>=ny) { cj=step_div(j,ny); y-=cj*by;x-=cj*bxy;j-=cj*ny; } else cj=0; ijk=step_int(x*xsp); if(ijk<0||ijk>=nx) { ci=step_div(ijk,nx); x-=ci*bx;ijk-=ci*nx; } else ci=0; ijk+=nx*(j+ny*k);double *pp(pts[ijk]); for(q=0;q (-1,0,0,1). * With this routine, we have (-1.5,-0.5,0.5,1.5) -> (-2,-1,0,1). */ inline int voronoi_network::step_int(double a) { return a<0?int(a)-1:int(a); } /** Custom integer division function, that gives consistent stepping for * negative numbers. */ inline int voronoi_network::step_div(int a,int b) { return a>=0?a/b:-1+(a+1)/b; } // Explicit instantiation template voronoi_network::voronoi_network(container_periodic&, double); template voronoi_network::voronoi_network(container_periodic_poly&, double); template void voronoi_network::add_to_network(voronoicell&, int, double, double, double, double); template void voronoi_network::add_to_network(voronoicell_neighbor&, int, double, double, double, double); template void voronoi_network::add_to_network_rectangular(voronoicell&, int, double, double, double, double); template void voronoi_network::add_to_network_rectangular(voronoicell_neighbor&, int, double, double, double, double);