/* Packing of hard spheres via molecular dynamics Developed by Monica Skoge, 2006, Princeton University Contact: Aleksandar Donev (adonev@math.princeton.edu) with questions This code may be used, modified and distributed freely. Please cite: "Packing Hyperspheres in High-Dimensional Euclidean Spaces" M. Skoge, A. Donev, F. H. Stillinger and S. Torquato, 2006 if you use these codes. */ #include "box.h" #include #include #include #include #include //============================================================== //============================================================== // Class Box: Fills box with hardspheres to given packing fraction // and evolves spheres using molecular dynamics! //============================================================== //============================================================== //============================================================== // Constructor //============================================================== box::box(int N_i, double r_i, double growthrate_i, double maxpf_i): r(r_i), N(N_i), growthrate(growthrate_i), h(N_i+1), maxpf(maxpf_i) { ngrids = Optimalngrids(maxpf); cells.set_size(ngrids); s = new sphere[N]; binlist = new int[N]; x = new vector[N]; h.s = s; gtime = 0.; rtime = 0.; ncollisions = 0; ntransfers = 0; nchecks = 0; neventstot = 0; ncycles = 0; xmomentum = 0.; pressure = 0.; cells.set_size(ngrids); cells.initialize(-1); // initialize cells to -1 srandom(::time(0)); // initialize the random number generator for (int i=0; i> s[i].x[k]; infile.close(); } //============================================================== // Recreates all N spheres at random positions //============================================================== void box::RecreateSpheres(const char* filename, double temp) { ReadPositions(filename); // reads in positions of spheres VelocityGiver(temp); // gives spheres initial velocities AssignCells(); // assigns spheres to cells SetInitialEvents(); } //============================================================== // Creates all N spheres at random positions //============================================================== void box::CreateSpheres(double temp) { int Ncurrent = 0; for(int i=0; i xrand; // random new position vector double d = 0.; while (counter<1000) { keeper = 1; for(int k=0; k= 1000) { std::cout << "counter >= 1000" << std::endl; exit(-1); } // now convert xrand into index vector for cells vector cell; cell = vector::integer(xrand*((double)(ngrids))/SIZE); s[Ncurrent] = sphere(Ncurrent, xrand, cell, gtime); //first check to see if entry at cell if (cells.get(cell) == -1) //if yes, add Ncurrent to cells gridfield cells.get(cell) = Ncurrent; else // if no, add i to right place in binlist { int iterater = cells.get(cell); // now iterate through to end and add Ncurrent int pointer = iterater; while (iterater != -1) { pointer = iterater; iterater = binlist[iterater]; } binlist[pointer] = Ncurrent; } Ncurrent++; } //============================================================== // Assign cells to spheres read in from existing configuration //============================================================== void box::AssignCells() { for (int i=0; i cell; cell = vector::integer(s[i].x*((double)(ngrids))/SIZE); s[i].cell = cell; //first check to see if entry at cell if (cells.get(cell) == -1) //if yes, add Ncurrent to cells gridfield cells.get(cell) = i; else // if no, add i to right place in binlist { int iterater = cells.get(cell); // now iterate through to end and add Ncurrent int pointer = iterater; while (iterater != -1) { pointer = iterater; iterater = binlist[iterater]; } binlist[pointer] = i; } } } //============================================================== // Velocity Giver, assigns initial velocities from Max/Boltz dist. //============================================================== void box::VelocityGiver(double T) { for (int i=0; i -10.*DBL_EPSILON) // this should happen only when reading in a configuration and spheres is on left boundary moving left //newtime = 0.; //else std::cout << "error in FindNextTransfer left newtime < 0 " << k << std::endl; } if (newtime vl, vector vr, neighbor& operation) { vector cell = s[i].cell; // now iterate through nearest neighbors vector offset; // nonnegative neighbor offset vector pboffset; // nearest image offset vector grid; int ii ; grid=vl; while(1) { //if (vr[0] > 1) //std::cout << grid << "..." << cell+grid << "\n"; for(int k=0; k=ngrids) // out of bounds to right pboffset[k] = 1; else pboffset[k] = 0; } int j = cells.get((cell+offset)%ngrids); while(j!=-1) { operation.Operation(j,pboffset); j = binlist[j]; } // A. Donev: // This code makes this loop dimension-independent // It is basically a flattened-out loop nest of depth DIM for(ii=0;ii=DIM) break; } } //============================================================== // PredictCollision //============================================================== void box::PredictCollision(int i, int j, vector pboffset, double& ctime, int& cpartner, vector& cpartnerpboffset) { double ctimej; if (i!=j) { ctimej = CalculateCollision(i,j,pboffset.Double())+gtime; if (ctimej < gtime) std::cout << "error in find collision ctimej < 0" << std::endl; if ((ctimej < ctime)&&(ctimej < s[j].nextevent.time)) { ctime = ctimej; cpartner = j; cpartnerpboffset = pboffset; if (pboffset.norm_squared() > 1E-15) { std::cout << "error!" << std::endl; exit(-1); } } } } //============================================================== // Find next collision //============================================================== event box::FindNextCollision(int i) { collision cc(i, this); vector vl, vr; for (int k=0; k pboffset) { if (pboffset.norm_squared() < 1E-15) { // calculate updated position and velocity of i and j vector xi = s[i].x + s[i].v*(gtime - s[i].lutime); vector vi = s[i].v; vector xj = s[j].x + pboffset*SIZE + s[j].v*(gtime - s[j].lutime); vector vj = s[j].v; double r_now = r + gtime*growthrate; double A,B,C; A = vector::norm_squared(vi - vj) - 4*growthrate*growthrate; B = vector::dot(xi - xj, vi - vj) - 4*r_now*growthrate; C = vector::norm_squared(xi - xj) - 4*r_now*r_now; if (C < -1E-12*2.*r_now) { std::cout << "error, " << i << " and " << j << " are overlapping at time "<< gtime << " and A, B, C = " << A << " " << " " << B << " " << " " << C << std::endl; std::cout << "velocity i= " << s[i].v << ", velocity j= " << s[j].v << ", gtime= " << gtime << ", det= " << B*B - A*C << std::endl; exit(-1); } return QuadraticFormula(A, B, C); } else return dblINF; } //============================================================== // Quadratic Formula ax^2 + bx + c = 0 //============================================================== double box::QuadraticFormula(double a, double b, double c) { double x = dblINF; double xpos; double xneg; double det = b*b - a*c; if (c <= 0.) { if(b < 0.) // spheres already overlapping and approaching { //std::cout << "spheres overlapping and approaching" << std::endl; //std::cout << "# events= " << neventstot << std::endl; x = 0.; } } else if (det > -10.*DBL_EPSILON) { if (det < 0.) // determinant can be very small for double roots det = 0.; if (b < 0.) x = c/(-b + sqrt(det)); else if ((a < 0.)&&(b > 0.)) x = -(b + sqrt(det))/a; else x = dblINF; } return x; } //============================================================== // Returns first event //============================================================== void box::ProcessEvent() { neventstot++; // Extract first event from heap int i = h.extractmax(); event e = s[i].nextevent; // current event event f; // replacement event if ((e.j>=0)&&(e.j vipar; // parallel comp. vi vector vjpar; // parallel comp. vj vector viperp; // perpendicular comp. vi vector vjperp; // perpendicular comp. vj // make unit vector out of displacement vector vector dhat; dhat = s[i].x - s[j].x - v.Double()*SIZE; // using image of j!! double dhatmagnitude = sqrt(dhat.norm_squared()); dhat /= dhatmagnitude; vipar = dhat*vector::dot(s[i].v, dhat); vjpar = dhat*vector::dot(s[j].v, dhat); viperp = s[i].v - vipar; vjperp = s[j].v - vjpar; s[i].v = vjpar + dhat*2.*growthrate + viperp; s[j].v = vipar - dhat*2.*growthrate + vjperp; // momentum exchange double xvelocity; // exchanged velocity xvelocity = vector::dot(s[i].v - s[j].v, dhat) - 4.*growthrate; xmomentum += M*xvelocity*dhatmagnitude; } //============================================================== // Transfer, takes care of boundary events too //============================================================= void box::Transfer(event e) { gtime = e.time; int i = e.i; int j = e.j; int k=0; // dimension perpendicular to wall it crosses // update position and lutime (velocity doesn't change) s[i].x += s[i].v*(gtime-s[i].lutime); s[i].lutime = gtime; vector celli; // new cell for i celli = s[i].cell; // this is not redundant // update cell if (j>N+DIM+1) // right wall { k = j-N-DIM-2; celli[k] = s[i].cell[k] + 1; // if in right-most cell, translate x and cell if (s[i].cell[k] == ngrids - 1) { //s[i].x[k] -= SIZE; //celli[k] -= ngrids; s[i].v[k] = -s[i].v[k] - 4.*growthrate; } else UpdateCell(i, celli); } else if (j& celli) { if (celli == s[i].cell) std::cout << "error in update cell..shouldn't be the same" << std::endl; // delete i from cell array at cell else if (cells.get(s[i].cell) == i) { if (binlist[i] == -1) cells.get(s[i].cell) = -1; else { cells.get(s[i].cell) = binlist[i]; binlist[i] = -1; } } else if (cells.get(s[i].cell) == -1) { std::cout << "error " << i << " not in claimed cell UpdateCell" << std::endl; OutputCells(); } else // if no, find i in binlist { int iterater = cells.get(s[i].cell); int pointer = iterater; while ((iterater != i)&&(iterater != -1)) { pointer = iterater; iterater = binlist[iterater]; } if (iterater == -1) // got to end of list without finding i { std::cout << "problem " << i << " wasn't in claimed, cell iterater = -1" << std::endl; OutputCells(); } else // we found i! { binlist[pointer] = binlist[i]; binlist[i] = -1; } } // now add i to cell array at celli s[i].cell = celli; //first check to see if entry at celli if (cells.get(celli) == -1) //if yes, add i to cells gridfield cells.get(celli) = i; else // if no, add i to right place in binlist { int iterater = cells.get(celli); // now iterate through to end and add i int pointer = iterater; while (iterater != -1) // find the end of the list { pointer = iterater; iterater = binlist[iterater]; } binlist[pointer] = i; binlist[i] = -1; // redundant } } //============================================================== // Output event heap...purely used for debugging //============================================================== void box::OutputEvents() { h.print(); } //============================================================== // Output positions of spheres and their cells...purely used for debugging //============================================================== void box::OutputCells() { for (int i=0; i