From 5ba4109f0021e7b2c9c66821461742a339e07355 Mon Sep 17 00:00:00 2001 From: pants Date: Wed, 7 Dec 2016 13:29:51 -0500 Subject: added support for hyperuniform lattices using existing hard-sphere jamming routine --- src/spheres_poly/box.cpp | 1157 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1157 insertions(+) create mode 100644 src/spheres_poly/box.cpp (limited to 'src/spheres_poly/box.cpp') diff --git a/src/spheres_poly/box.cpp b/src/spheres_poly/box.cpp new file mode 100644 index 0000000..716090d --- /dev/null +++ b/src/spheres_poly/box.cpp @@ -0,0 +1,1157 @@ +/* + Updated July 24, 2009 to include hardwall boundary condition option, as + well as polydisperse spheres. + + Packing of hard spheres via molecular dynamics + Developed by Monica Skoge, 2006, Princeton University + Contact: Monica Skoge (mskoge.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, + double bidispersityratio_i, double bidispersityfraction_i, + double massratio_i, int hardwallBC_i): + r(r_i), + N(N_i), + growthrate(growthrate_i), + h(N_i+1), + maxpf(maxpf_i), + bidispersityratio(bidispersityratio_i), + bidispersityfraction(bidispersityfraction_i), + massratio(massratio_i), + hardwallBC(hardwallBC_i) +{ + ngrids = Optimalngrids2(r); + 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.; + collisionrate = 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].r; // read in radius + infile >> s[i].gr; // read in growth rate + infile >> s[i].m; // read in mass + for (int k=0; k> s[i].x[k]; // read in position + } + 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.; + double radius; + double growth_rate; + double mass; + int species; + + if (Ncurrent < bidispersityfraction*N) + { + radius = r; + growth_rate = growthrate; + mass = 1.; + species = 1; + } + else + { + radius = r*bidispersityratio; + growth_rate = growthrate*bidispersityratio; + mass = massratio; + species = 2; + } + + while (counter<1000) + { + keeper = 1; + + for(int k=0; k SIZE*SIZE/4.) + { + if (xrand[k] > SIZE/2.) // look at right image + d += (xrand[k] - (s[i].x[k]+SIZE))* + (xrand[k] - (s[i].x[k]+SIZE)); + else // look at left image + d += (xrand[k] - (s[i].x[k]-SIZE))* + (xrand[k] - (s[i].x[k]-SIZE)); + } + else + d += (xrand[k] - s[i].x[k])*(xrand[k] - s[i].x[k]); + } + } + if (d <= (radius + s[i].r)*(radius + s[i].r)) // overlapping! + { + keeper = 0; + counter++; + break; + } + } + + if (hardwallBC) + { + 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, radius, growth_rate, + mass, species); + + //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; + } + +} + + +//============================================================== +// 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; i1)) + { + event o = event(outgrowtime,i,INF-1); + return o; + } + + if ((c.time < t.time)&&(c.j == INF)) // next event is check at DBL infinity + return c; + else if (c.time < t.time) // next event is collision! + { + CollisionChecker(c); + return c; + } + else // next event is transfer! + return t; +} + + +//============================================================== +// Checks events of predicted collision partner to keep collisions +// symmetric +//============================================================== +void box::CollisionChecker(event c) +{ + int i = c.i; + int j = c.j; + event cj(c.time,j,i,c.v*(-1)); + + // j should have NO event before collision with i! + if (!(c.time < s[j].nextevent.time)) + std::cout << i << " " << j << " error collchecker, s[j].nextevent.time= " << s[j].nextevent.time << " " << s[j].nextevent.j << ", c.time= " << c.time << std::endl; + + int k = s[j].nextevent.j; + if ((k < N) && (k!=i)) // j's next event was collision so give k a check + s[k].nextevent.j = INF; + + // give collision cj to j + s[j].nextevent = cj; + h.upheap(h.index[j]); +} + + +//============================================================== +// Find next transfer for sphere i +//============================================================== +event box::FindNextTransfer(int i) +{ + double ttime = dblINF; + int wallindex = INF; // -(k+1) left wall, (k+1) right wall + + vector xi = s[i].x + s[i].v*(gtime - s[i].lutime); + vector vi = s[i].v; + + for (int k=0; k0) // will hit right wall, need to check if last wall + { + if ((hardwallBC)&&(s[i].cell[k] == ngrids - 1)) + newtime = ((double)(s[i].cell[k]+1)*SIZE/((double)(ngrids)) + - (xi[k]+s[i].r+s[i].gr*gtime))/(vi[k]+s[i].gr); + else + newtime = ((double)(s[i].cell[k]+1)*SIZE/((double)(ngrids)) + - xi[k])/(vi[k]); + + 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; + } + } +} + + +//============================================================== +// Find next collision +//============================================================== +event box::FindNextCollision(int i) +{ + collision cc(i, this); + + vector vl, vr; + + for (int k=0; k pboffset) +{ + if ((hardwallBC)&&(pboffset.norm_squared() > 1E-12)) + { + return dblINF; + } + else + { + // 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_i = s[i].r + gtime*s[i].gr; + double r_now_j = s[j].r + gtime*s[j].gr; + + double A,B,C; + A = vector::norm_squared(vi - vj) - (s[i].gr+s[j].gr)*(s[i].gr+s[j].gr); + B = vector::dot(xi - xj, vi - vj) - (r_now_i+r_now_j)*(s[i].gr+s[j].gr); + C = vector::norm_squared(xi - xj) - (r_now_i+r_now_j)*(r_now_i+r_now_j); + + if (C < -1E-12*(r_now_i+r_now_j)) + { + std::cout << "error, " << i << " and " << j << + " are overlapping at time "<< gtime << std::cout; + std::cout << "A, B, C = " << A << " " << " " << B << + " " << " " << C << std::endl; + if (CheckSphereDiameters()>0) + std::cout << "a sphere has grown greater than unit cell" << + std::endl; + else + std::cout << "unknown error" << std::cout; + exit(-1); + } + + return QuadraticFormula(A, B, C); + } +} + + +//============================================================== +// 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*(s[i].gr+s[j].gr)*2 + viperp; + s[j].v = vipar - dhat*(s[i].gr+s[j].gr)*2 + vjperp; + + // momentum exchange + double xvelocity; // exchanged velocity + xvelocity = vector::dot(s[i].v - s[j].v, dhat) - (s[i].gr+s[j].gr); + xmomentum += xvelocity*dhatmagnitude*s[i].m*s[j].m*2/(s[i].m+s[j].m); +} + + +//============================================================== +// 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 (hardwallBC) + { + // if in right-most cell, reflect back + if (s[i].cell[k] == ngrids - 1) + s[i].v[k] = -s[i].v[k] - 4.*s[i].gr; + else + { + if (ngrids>1) + UpdateCell(i, celli); + } + } + else + { + // if in right-most cell, translate x and cell + if (s[i].cell[k] == ngrids - 1) + { + s[i].x[k] -= SIZE; + celli[k] -= ngrids; + } + if (ngrids>1) + UpdateCell(i, celli); + } + } + else if (j1) + UpdateCell(i, celli); + } + } + else + { + // if in left-most cell, translate x and cell + if (s[i].cell[k] == 0) + { + s[i].x[k] += SIZE; + celli[k] += ngrids; + } + if (ngrids>1) + UpdateCell(i, celli); + } + } + else + std::cout << "error in Transfer" << std::endl; + +} + + +//============================================================== +// Updates cell of a sphere to time +//============================================================= +void box::UpdateCell(int i, vector& 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 + + 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 1./ngrids){ + offender = i; + break; + } + } + return offender; +} + + +//============================================================== +// Change ngrids +//============================================================== +void box::ChangeNgrids(int newngrids) +{ + cells.set_size(newngrids); + cells.initialize(-1); // initialize cells to -1 + for (int i=0; i