Voro++
pre_container.cc
Go to the documentation of this file.
00001 // Voro++, a 3D cell-based Voronoi library
00002 //
00003 // Author   : Chris H. Rycroft (LBL / UC Berkeley)
00004 // Email    : chr@alum.mit.edu
00005 // Date     : August 30th 2011
00006 
00007 /** \file pre_container.cc
00008  * \brief Function implementations for the pre_container and related classes.
00009  */
00010 
00011 #include <cstdio>
00012 #include <cmath>
00013 using namespace std;
00014 
00015 #include "config.hh"
00016 #include "pre_container.hh"
00017 
00018 namespace voro {
00019 
00020 /** The class constructor sets up the geometry of container, initializing the
00021  * minimum and maximum coordinates in each direction. It allocates an initial
00022  * chunk into which to store particle information.
00023  * \param[in] (ax_,bx_) the minimum and maximum x coordinates.
00024  * \param[in] (ay_,by_) the minimum and maximum y coordinates.
00025  * \param[in] (az_,bz_) the minimum and maximum z coordinates.
00026  * \param[in] (xperiodic_,yperiodic_,zperiodic_ ) flags setting whether the
00027  *                                                container is periodic in each
00028  *                                                coordinate direction.
00029  * \param[in] ps_ the number of floating point entries to store for each
00030  *                particle. */
00031 pre_container_base::pre_container_base(double ax_,double bx_,double ay_,double by_,double az_,double bz_,
00032         bool xperiodic_,bool yperiodic_,bool zperiodic_,int ps_) :
00033         ax(ax_), bx(bx_), ay(ay_), by(by_), az(az_), bz(bz_),
00034         xperiodic(xperiodic_), yperiodic(yperiodic_), zperiodic(zperiodic_), ps(ps_),
00035         index_sz(init_chunk_size), pre_id(new int*[index_sz]), end_id(pre_id),
00036         pre_p(new double*[index_sz]), end_p(pre_p) {
00037                 ch_id=*end_id=new int[pre_container_chunk_size];
00038                 l_id=end_id+index_sz;e_id=ch_id+pre_container_chunk_size;
00039                 ch_p=*end_p=new double[ps*pre_container_chunk_size];
00040 }
00041 
00042 /** The destructor frees the dynamically allocated memory. */
00043 pre_container_base::~pre_container_base() {
00044         delete [] *end_p;
00045         delete [] *end_id;
00046         while (end_id!=pre_id) {
00047                 end_p--;
00048                 delete [] *end_p;
00049                 end_id--;
00050                 delete [] *end_id;
00051         }
00052         delete [] pre_p;
00053         delete [] pre_id;
00054 }
00055 
00056 /** Makes a guess at the optimal grid of blocks to use, computing in
00057  * a way that
00058  * \param[out] (nx,ny,nz) the number of blocks to use. */
00059 void pre_container_base::guess_optimal(int &nx,int &ny,int &nz) {
00060         double dx(bx-ax),dy(by-ay),dz(bz-az);
00061         double ilscale(pow(total_particles()/(optimal_particles*dx*dy*dz),1/3.0));
00062         nx=int(dx*ilscale+1);
00063         ny=int(dy*ilscale+1);
00064         nz=int(dz*ilscale+1);
00065 }
00066 
00067 /** Stores a particle ID and position, allocating a new memory chunk if
00068  * necessary. For coordinate directions in which the container is not periodic,
00069  * the routine checks to make sure that the particle is within the container
00070  * bounds. If the particle is out of bounds, it is not stored.
00071  * \param[in] n the numerical ID of the inserted particle.
00072  * \param[in] (x,y,z) the position vector of the inserted particle. */
00073 void pre_container::put(int n,double x,double y,double z) {
00074         if((xperiodic||(x>=ax&&x<=bx))&&(yperiodic||(y>=ay&&y<=by))&&(zperiodic||(z>=az&&z<=bz))) {
00075                 if(ch_id==e_id) new_chunk();
00076                 *(ch_id++)=n;
00077                 *(ch_p++)=x;*(ch_p++)=y;*(ch_p++)=z;
00078         }
00079 #if VOROPP_REPORT_OUT_OF_BOUNDS ==1
00080         else fprintf(stderr,"Out of bounds: (x,y,z)=(%g,%g,%g)\n",x,y,z);
00081 #endif
00082 }
00083 
00084 /** Stores a particle ID and position, allocating a new memory chunk if necessary.
00085  * \param[in] n the numerical ID of the inserted particle.
00086  * \param[in] (x,y,z) the position vector of the inserted particle.
00087  * \param[in] r the radius of the particle. */
00088 void pre_container_poly::put(int n,double x,double y,double z,double r) {
00089         if((xperiodic||(x>=ax&&x<=bx))&&(yperiodic||(y>=ay&&y<=by))&&(zperiodic||(z>=az&&z<=bz))) {
00090                 if(ch_id==e_id) new_chunk();
00091                 *(ch_id++)=n;
00092                 *(ch_p++)=x;*(ch_p++)=y;*(ch_p++)=z;*(ch_p++)=r;
00093         }
00094 #if VOROPP_REPORT_OUT_OF_BOUNDS ==1
00095         else fprintf(stderr,"Out of bounds: (x,y,z)=(%g,%g,%g)\n",x,y,z);
00096 #endif
00097 }
00098 
00099 /** Transfers the particles stored within the class to a container class.
00100  * \param[in] con the container class to transfer to. */
00101 void pre_container::setup(container &con) {
00102         int **c_id=pre_id,*idp,*ide,n;
00103         double **c_p=pre_p,*pp,x,y,z;
00104         while(c_id<end_id) {
00105                 idp=*(c_id++);ide=idp+pre_container_chunk_size;
00106                 pp=*(c_p++);
00107                 while(idp<ide) {
00108                         n=*(idp++);x=*(pp++);y=*(pp++);z=*(pp++);
00109                         con.put(n,x,y,z);
00110                 }
00111         }
00112         idp=*c_id;
00113         pp=*c_p;
00114         while(idp<ch_id) {
00115                 n=*(idp++);x=*(pp++);y=*(pp++);z=*(pp++);
00116                 con.put(n,x,y,z);
00117         }
00118 }
00119 
00120 /** Transfers the particles stored within the class to a container_poly class.
00121  * \param[in] con the container_poly class to transfer to. */
00122 void pre_container_poly::setup(container_poly &con) {
00123         int **c_id=pre_id,*idp,*ide,n;
00124         double **c_p=pre_p,*pp,x,y,z,r;
00125         while(c_id<end_id) {
00126                 idp=*(c_id++);ide=idp+pre_container_chunk_size;
00127                 pp=*(c_p++);
00128                 while(idp<ide) {
00129                         n=*(idp++);x=*(pp++);y=*(pp++);z=*(pp++);r=*(pp++);
00130                         con.put(n,x,y,z,r);
00131                 }
00132         }
00133         idp=*c_id;
00134         pp=*c_p;
00135         while(idp<ch_id) {
00136                 n=*(idp++);x=*(pp++);y=*(pp++);z=*(pp++);r=*(pp++);
00137                 con.put(n,x,y,z,r);
00138         }
00139 }
00140 
00141 /** Transfers the particles stored within the class to a container class, also
00142  * recording the order in which particles were stored.
00143  * \param[in] vo the ordering class to use.
00144  * \param[in] con the container class to transfer to. */
00145 void pre_container::setup(particle_order &vo,container &con) {
00146         int **c_id=pre_id,*idp,*ide,n;
00147         double **c_p=pre_p,*pp,x,y,z;
00148         while(c_id<end_id) {
00149                 idp=*(c_id++);ide=idp+pre_container_chunk_size;
00150                 pp=*(c_p++);
00151                 while(idp<ide) {
00152                         n=*(idp++);x=*(pp++);y=*(pp++);z=*(pp++);
00153                         con.put(vo,n,x,y,z);
00154                 }
00155         }
00156         idp=*c_id;
00157         pp=*c_p;
00158         while(idp<ch_id) {
00159                 n=*(idp++);x=*(pp++);y=*(pp++);z=*(pp++);
00160                 con.put(vo,n,x,y,z);
00161         }
00162 }
00163 
00164 /** Transfers the particles stored within the class to a container_poly class,
00165  * also recording the order in which particles were stored.
00166  * \param[in] vo the ordering class to use.
00167  * \param[in] con the container_poly class to transfer to. */
00168 void pre_container_poly::setup(particle_order &vo,container_poly &con) {
00169         int **c_id=pre_id,*idp,*ide,n;
00170         double **c_p=pre_p,*pp,x,y,z,r;
00171         while(c_id<end_id) {
00172                 idp=*(c_id++);ide=idp+pre_container_chunk_size;
00173                 pp=*(c_p++);
00174                 while(idp<ide) {
00175                         n=*(idp++);x=*(pp++);y=*(pp++);z=*(pp++);r=*(pp++);
00176                         con.put(vo,n,x,y,z,r);
00177                 }
00178         }
00179         idp=*c_id;
00180         pp=*c_p;
00181         while(idp<ch_id) {
00182                 n=*(idp++);x=*(pp++);y=*(pp++);z=*(pp++);r=*(pp++);
00183                 con.put(vo,n,x,y,z,r);
00184         }
00185 }
00186 
00187 /** Import a list of particles from an open file stream into the container.
00188  * Entries of four numbers (Particle ID, x position, y position, z position)
00189  * are searched for. If the file cannot be successfully read, then the routine
00190  * causes a fatal error.
00191  * \param[in] fp the file handle to read from. */
00192 void pre_container::import(FILE *fp) {
00193         int i,j;
00194         double x,y,z;
00195         while((j=fscanf(fp,"%d %lg %lg %lg",&i,&x,&y,&z))==4) put(i,x,y,z);
00196         if(j!=EOF) voro_fatal_error("File import error",VOROPP_FILE_ERROR);
00197 }
00198 
00199 /** Import a list of particles from an open file stream, also storing the order
00200  * of that the particles are read. Entries of four numbers (Particle ID, x
00201  * position, y position, z position) are searched for. If the file cannot be
00202  * successfully read, then the routine causes a fatal error.
00203  * \param[in] fp the file handle to read from. */
00204 void pre_container_poly::import(FILE *fp) {
00205         int i,j;
00206         double x,y,z,r;
00207         while((j=fscanf(fp,"%d %lg %lg %lg %lg",&i,&x,&y,&z,&r))==5) put(i,x,y,z,r);
00208         if(j!=EOF) voro_fatal_error("File import error",VOROPP_FILE_ERROR);
00209 }
00210 
00211 /** Allocates a new chunk of memory for storing particles. */
00212 void pre_container_base::new_chunk() {
00213         end_id++;end_p++;
00214         if(end_id==l_id) extend_chunk_index();
00215         ch_id=*end_id=new int[pre_container_chunk_size];
00216         e_id=ch_id+pre_container_chunk_size;
00217         ch_p=*end_p=new double[ps*pre_container_chunk_size];
00218 }
00219 
00220 /** Extends the index of chunks. */
00221 void pre_container_base::extend_chunk_index() {
00222         index_sz<<=1;
00223         if(index_sz>max_chunk_size)
00224                 voro_fatal_error("Absolute memory limit on chunk index reached",VOROPP_MEMORY_ERROR);
00225 #if VOROPP_VERBOSE >=2
00226         fprintf(stderr,"Pre-container chunk index scaled up to %d\n",index_sz);
00227 #endif
00228         int **n_id=new int*[index_sz],**p_id=n_id,**c_id=pre_id;
00229         double **n_p=new double*[index_sz],**p_p=n_p,**c_p=pre_p;
00230         while(c_id<end_id) {
00231                 *(p_id++)=*(c_id++);
00232                 *(p_p++)=*(c_p++);
00233         }
00234         delete [] pre_id;pre_id=n_id;end_id=p_id;l_id=pre_id+index_sz;
00235         delete [] pre_p;pre_p=n_p;end_p=p_p;
00236 }
00237 
00238 }