tcleaned up sphere.py - sphere - GPU-based 3D discrete element method algorithm… | |
git clone git://src.adamsgaard.dk/sphere | |
Log | |
Files | |
Refs | |
LICENSE | |
--- | |
commit 5102e7af6943a2455722007fe607995c52795593 | |
parent c78431e98828434d0b07230d51e5a8bfdba8ab65 | |
Author: Anders Damsgaard Christensen <[email protected]> | |
Date: Wed, 3 Apr 2013 12:04:08 +0200 | |
cleaned up sphere.py | |
Diffstat: | |
M python/sphere.py | 122 +++++++++++++----------------… | |
1 file changed, 52 insertions(+), 70 deletions(-) | |
--- | |
diff --git a/python/sphere.py b/python/sphere.py | |
t@@ -10,9 +10,9 @@ import subprocess | |
numpy.seterr(all='warn', over='raise') | |
class Spherebin: | |
- """ | |
+ """ | |
Class containing all data SPHERE data. | |
- | |
+ | |
Contains functions for reading and writing binaries, as well as simulation | |
setup and data analysis. | |
""" | |
t@@ -181,8 +181,6 @@ class Spherebin: | |
else : | |
return 1 | |
- | |
- | |
def readbin(self, targetbin, verbose = True, bonds = True, devsmod = True): | |
'Reads a target SPHERE binary file' | |
t@@ -257,13 +255,13 @@ class Spherebin: | |
self.gamma_n = numpy.fromfile(fh, dtype=numpy.float64, count=… | |
self.gamma_t = numpy.fromfile(fh, dtype=numpy.float64, count=… | |
self.gamma_r = numpy.fromfile(fh, dtype=numpy.float64, count=… | |
- self.mu_s = numpy.fromfile(fh, dtype=numpy.float64, count=… | |
- self.mu_d = numpy.fromfile(fh, dtype=numpy.float64, count=… | |
+ self.mu_s = numpy.fromfile(fh, dtype=numpy.float64, count=… | |
+ self.mu_d = numpy.fromfile(fh, dtype=numpy.float64, count=… | |
self.mu_r = numpy.fromfile(fh, dtype=numpy.float64, count=… | |
self.gamma_wn = numpy.fromfile(fh, dtype=numpy.float64, count=… | |
self.gamma_wt = numpy.fromfile(fh, dtype=numpy.float64, count=… | |
- self.mu_ws = numpy.fromfile(fh, dtype=numpy.float64, count=… | |
- self.mu_wd = numpy.fromfile(fh, dtype=numpy.float64, count=… | |
+ self.mu_ws = numpy.fromfile(fh, dtype=numpy.float64, count=… | |
+ self.mu_wd = numpy.fromfile(fh, dtype=numpy.float64, count=… | |
self.rho = numpy.fromfile(fh, dtype=numpy.float64, count=… | |
self.contactmodel = numpy.fromfile(fh, dtype=numpy.uint32, count=1) | |
self.kappa = numpy.fromfile(fh, dtype=numpy.float64, count=… | |
t@@ -458,7 +456,6 @@ class Spherebin: | |
fig.savefig('psd.png') | |
fig.clf() | |
- | |
def generateBimodalRadii(self, | |
r_small = 0.005, | |
r_large = 0.05, | |
t@@ -467,7 +464,7 @@ class Spherebin: | |
""" Draw radii from two sizes | |
@param r_small: Radii of small population (float), in ]0;r_large[ | |
@param r_large: Radii of large population (float), in ]r_small;inf[ | |
- @param ratio: Approximate volumetric ratio between the two | |
+ @param ratio: Approximate volumetric ratio between the two | |
populations (large/small). | |
""" | |
if (r_small >= r_large): | |
t@@ -491,7 +488,7 @@ class Spherebin: | |
print("generateBimodalRadii created " + str(nlarge) + " large part… | |
- def initRandomPos(self, g = numpy.array([0.0, 0.0, -9.80665]), | |
+ def initRandomPos(self, g = numpy.array([0.0, 0.0, -9.80665]), | |
gridnum = numpy.array([12, 12, 36]), | |
periodic = 1, | |
contactmodel = 2): | |
t@@ -584,7 +581,7 @@ class Spherebin: | |
numpy.amax(self.x[:,2] + self.radius[:])]) \ | |
+ margin*r_max | |
- cellsize_min = 2.1 * r_max | |
+ cellsize_min = 2.1 * r_max | |
self.num[0] = numpy.ceil((self.L[0]-self.origo[0])/cellsize_min) | |
self.num[1] = numpy.ceil((self.L[1]-self.origo[1])/cellsize_min) | |
self.num[2] = numpy.ceil((self.L[2]-self.origo[2])/cellsize_min) | |
t@@ -601,7 +598,7 @@ class Spherebin: | |
# Initialize particle positions to regular, grid-like, non-overlapping con… | |
- def initGridPos(self, g = numpy.array([0.0, 0.0, -9.80665]), | |
+ def initGridPos(self, g = numpy.array([0.0, 0.0, -9.80665]), | |
gridnum = numpy.array([12, 12, 36]), | |
periodic = 1, | |
contactmodel = 2): | |
t@@ -621,7 +618,7 @@ class Spherebin: | |
cellsize = 2.1 * r_max | |
self.L = self.num * cellsize | |
- # Check whether there are enough grid cells | |
+ # Check whether there are enough grid cells | |
if ((self.num[0]*self.num[1]*self.num[2]-(2**3)) < self.np): | |
print("Error! The grid is not sufficiently large.") | |
raise NameError('Error! The grid is not sufficiently large.') | |
t@@ -633,7 +630,7 @@ class Spherebin: | |
self.num[0] -= 1 | |
self.num[1] -= 1 | |
- # Check whether there are enough grid cells | |
+ # Check whether there are enough grid cells | |
if ((self.num[0]*self.num[1]*self.num[2]-(2*3*3)) < self.np): | |
print("Error! The grid is not sufficiently large.") | |
raise NameError('Error! The grid is not sufficiently large.') | |
t@@ -666,7 +663,7 @@ class Spherebin: | |
self.num[1] += 1 | |
- def initRandomGridPos(self, g = numpy.array([0.0, 0.0, -9.80665]), | |
+ def initRandomGridPos(self, g = numpy.array([0.0, 0.0, -9.80665]), | |
gridnum = numpy.array([12, 12, 32]), | |
periodic = 1, | |
contactmodel = 2): | |
t@@ -679,13 +676,13 @@ class Spherebin: | |
self.periodic[0] = periodic | |
# Calculate cells in grid | |
- coarsegrid = numpy.floor(gridnum/2) | |
+ coarsegrid = numpy.floor(gridnum/2) | |
- # World size | |
+ # World size | |
r_max = numpy.amax(self.radius) | |
cellsize = 2.1 * r_max * 2 # Cells in grid 2*size to make space for ra… | |
- # Check whether there are enough grid cells | |
+ # Check whether there are enough grid cells | |
if (((coarsegrid[0]-1)*(coarsegrid[1]-1)*(coarsegrid[2]-1)) < self.np): | |
print("Error! The grid is not sufficiently large.") | |
raise NameError('Error! The grid is not sufficiently large.') | |
t@@ -721,8 +718,8 @@ class Spherebin: | |
def createBondPair(self, i, j, spacing=-0.1): | |
""" Bond particles i and j. Particle j is moved adjacent to particle i, | |
- and oriented randomly. | |
- @param spacing (float) The inter-particle distance prescribed. Positiv… | |
+ and oriented randomly. | |
+ @param spacing (float) The inter-particle distance prescribed. Positive | |
values result in a inter-particle distance, negative equal an overlap. | |
The value is relative to the sum of the two radii. | |
""" | |
t@@ -758,7 +755,7 @@ class Spherebin: | |
self.x[j,2] -= abs(x_j[2] - x_i[2]) | |
self.bond(i,j) # register bond | |
- | |
+ | |
# Check that the spacing is correct | |
x_ij = self.x[i] - self.x[j] | |
x_ij_length = numpy.sqrt(x_ij.dot(x_ij)) | |
t@@ -772,13 +769,13 @@ class Spherebin: | |
def random2bonds(self, ratio=0.3, spacing=-0.1): | |
""" Bond an amount of particles in two-particle clusters | |
@param ratio: The amount of particles to bond, values in ]0.0;1.0] (fl… | |
- @param spacing: The distance relative to the sum of radii between bond… | |
+ @param spacing: The distance relative to the sum of radii between bond… | |
particles, neg. values denote an overlap. Values in ]0.0,inf[ (float). | |
The particles should be initialized beforehand. | |
- Note: The actual number of bonds is likely to be somewhat smaller than | |
+ Note: The actual number of bonds is likely to be somewhat smaller than | |
specified, due to the random selection algorithm. | |
""" | |
- | |
+ | |
bondparticles = numpy.unique(numpy.random.random_integers(0, high=self… | |
if (bondparticles.size % 2 > 0): | |
bondparticles = bondparticles[:-1].copy() | |
t@@ -786,7 +783,6 @@ class Spherebin: | |
for n in numpy.arange(bondparticles.shape[0]): | |
self.createBondPair(bondparticles[n,0], bondparticles[n,1], spacin… | |
- | |
def zeroKinematics(self): | |
'Zero kinematics of particles' | |
t@@ -802,7 +798,6 @@ class Spherebin: | |
self.xysum = numpy.zeros(self.np*2, dtype=numpy.float64)\ | |
.reshape(self.np, 2) | |
- | |
def adjustUpperWall(self, z_adjust = 1.1): | |
'Adjust grid and dynamic upper wall to max. particle height' | |
t@@ -822,13 +817,12 @@ class Spherebin: | |
self.w_m = numpy.array([self.rho[0] * self.np * math.pi * (cellsize/2.… | |
self.w_vel = numpy.zeros(1) | |
self.w_force = numpy.zeros(1) | |
- self.w_devs = numpy.zeros(1) | |
- | |
+ self.w_devs = numpy.zeros(1) | |
- def consolidate(self, deviatoric_stress = 10e3, | |
+ def consolidate(self, deviatoric_stress = 10e3, | |
periodic = 1): | |
- """ Setup consolidation experiment. Specify the upper wall | |
+ """ Setup consolidation experiment. Specify the upper wall | |
deviatoric stress in Pascal, default value is 10 kPa. | |
""" | |
t@@ -842,10 +836,9 @@ class Spherebin: | |
self.wmode = numpy.array([1]) | |
self.w_devs = numpy.ones(1) * deviatoric_stress | |
- | |
def uniaxialStrainRate(self, wvel = -0.001, | |
periodic = 1): | |
- """ Setup consolidation experiment. Specify the upper wall | |
+ """ Setup consolidation experiment. Specify the upper wall | |
velocity in m/s, default value is -0.001 m/s (i.e. downwards). | |
""" | |
t@@ -857,11 +850,10 @@ class Spherebin: | |
self.wmode = numpy.array([2]) # strain rate BC | |
self.w_vel = numpy.array([wvel]) | |
- | |
def shear(self, | |
shear_strain_rate = 1, | |
periodic = 1): | |
- """ Setup shear experiment. Specify the upper wall | |
+ """ Setup shear experiment. Specify the upper wall | |
deviatoric stress in Pascal, default value is 10 kPa. | |
The shear strain rate is the shear length divided by the | |
initial height per second. | |
t@@ -912,7 +904,6 @@ class Spherebin: | |
self.mu_ws[0] = 0.0 | |
self.mu_wd[0] = 0.0 | |
- | |
def initTemporal(self, total, | |
current = 0.0, | |
file_dt = 0.05, | |
t@@ -935,8 +926,7 @@ class Spherebin: | |
self.time_file_dt[0] = file_dt | |
self.time_step_count[0] = 0 | |
- | |
- def defaultParams(self, | |
+ def defaultParams(self, | |
mu_s = 0.4, | |
mu_d = 0.4, | |
mu_r = 0.0, | |
t@@ -1021,7 +1011,7 @@ class Spherebin: | |
""" Create a bond between particles i and j """ | |
self.lambda_bar[0] = 1.0 # Radius multiplier to parallel-bond radii | |
- | |
+ | |
if (hasattr(self, 'bonds') == False): | |
self.bonds = numpy.array([[i,j]], dtype=numpy.uint32) | |
else : | |
t@@ -1056,7 +1046,6 @@ class Spherebin: | |
''' Return current magnitude of the deviatoric normal stress ''' | |
return w_devs[0] + w_devs_A * numpy.sin(2.0 * numpy.pi * self.time_cur… | |
- | |
def energy(self, method): | |
""" Calculate the sum of the energy components of all particles. | |
""" | |
t@@ -1121,7 +1110,6 @@ class Spherebin: | |
e = (V_t - V_s)/V_s | |
return e | |
- | |
def bulkPorosity(self): | |
""" Calculate and return the bulk porosity """ | |
t@@ -1135,7 +1123,6 @@ class Spherebin: | |
# Find the volume of solids | |
V_solid = numpy.sum(V_sphere(self.radius)) | |
return (V_total - V_solid) / V_total | |
- | |
def porosity(self, | |
slices = 10, | |
t@@ -1173,7 +1160,6 @@ class Spherebin: | |
return numpy.array(porosity), numpy.array(depth) | |
- | |
def run(self, verbose=True, hideinputfile=False, dry=False, valgrind=False… | |
'Execute sphere with target project' | |
t@@ -1198,9 +1184,8 @@ class Spherebin: | |
if (status != 0): | |
raise Exception("Error, the sphere run returned with status " + st… | |
- | |
- def torqueScript(self, | |
- email="[email protected]", | |
+ def torqueScript(self, | |
+ email="[email protected]", | |
email_alerts="ae", | |
walltime="24:00:00", | |
queue="qfermi", | |
t@@ -1240,7 +1225,6 @@ class Spherebin: | |
if fh is not None: | |
fh.close() | |
- | |
def render(self, | |
method = "pres", | |
max_val = 1e3, | |
t@@ -1277,7 +1261,6 @@ class Spherebin: | |
# The shear velocity is the x-axis velocity value of the upper particl… | |
return self.vel[fixvel,0].max() | |
- | |
def shearstrain(self): | |
'Calculates and returns the current shear strain (gamma) value of the … | |
t@@ -1293,9 +1276,9 @@ class Spherebin: | |
def forcechains(self, lc=200.0, uc=650.0, outformat='png', disp='2d'): | |
''' Visualizes the force chains in the system from the magnitude of the | |
normal contact forces, and produces an image of them. | |
- @param lc: Lower cutoff of contact forces. Contacts below are not | |
+ @param lc: Lower cutoff of contact forces. Contacts below are not | |
visualized (float) | |
- @param uc: Upper cutoff of contact forces. Contacts above are | |
+ @param uc: Upper cutoff of contact forces. Contacts above are | |
visualized with this value (float) | |
@param outformat: Format of output image. Possible values are | |
'interactive', 'png', 'epslatex', 'epslatex-color' | |
t@@ -1336,7 +1319,7 @@ class Spherebin: | |
strikelist = [] # strike direction of the normal vector, [0:360[ | |
diplist = [] # dip of the normal vector, [0:90] | |
for i in I[0]: | |
- | |
+ | |
x1 = data[i,0] | |
y1 = data[i,1] | |
z1 = data[i,2] | |
t@@ -1359,14 +1342,14 @@ class Spherebin: | |
# Find dip angle | |
diplist.append(math.degrees(math.atan((zupper - zlower)/dhoriz))) | |
- | |
+ | |
# Find strike angle | |
if (ylower >= yupper): # in first two quadrants | |
strikelist.append(math.acos(dx/dhoriz)) | |
else : | |
strikelist.append(2.0*numpy.pi - math.acos(dx/dhoriz)) | |
- | |
+ | |
plt.figure(figsize=[4,4]) | |
ax = plt.subplot(111, polar=True, axisbg="w") | |
ax.scatter(strikelist, diplist, c='k', marker='+') | |
t@@ -1383,9 +1366,9 @@ class Spherebin: | |
strikelist = [] # strike direction of the normal vector, [0:360[ | |
diplist = [] # dip of the normal vector, [0:90] | |
for n in numpy.arange(self.nb0): | |
- | |
- i = self.bonds[n,0] | |
- j = self.bonds[n,1] | |
+ | |
+ i = self.bonds[n,0] | |
+ j = self.bonds[n,1] | |
x1 = self.x[i,0] | |
y1 = self.x[i,1] | |
t@@ -1409,14 +1392,14 @@ class Spherebin: | |
# Find dip angle | |
diplist.append(math.degrees(math.atan((zupper - zlower)/dhoriz))) | |
- | |
+ | |
# Find strike angle | |
if (ylower >= yupper): # in first two quadrants | |
strikelist.append(math.acos(dx/dhoriz)) | |
else : | |
strikelist.append(2.0*numpy.pi - math.acos(dx/dhoriz)) | |
- | |
+ | |
plt.figure(figsize=[4,4]) | |
ax = plt.subplot(111, polar=True, axisbg="w") | |
ax.scatter(strikelist, diplist, c='k', marker='+') | |
t@@ -1425,7 +1408,6 @@ class Spherebin: | |
plt.savefig("bonds-" + self.sid + "-rose.pdf", transparent=True) | |
- | |
def thinsection_x1x3(self, | |
x2 = 'center', | |
graphicsformat = 'png', | |
t@@ -1469,14 +1451,14 @@ class Spherebin: | |
# Loop over all particles, find intersections | |
for i in range(self.np): | |
- | |
+ | |
delta = abs(self.x[i,1] - x2) # distance between centre and plane | |
if (delta < self.radius[i]): # if the sphere intersects the plane | |
# Store particle index | |
ilist.append(i) | |
- | |
+ | |
# Store position on plane | |
xlist.append(self.x[i,0]) | |
ylist.append(self.x[i,2]) | |
t@@ -1533,7 +1515,7 @@ class Spherebin: | |
for (x, y, r, p) in zip(xlist, ylist, rlist, plist): | |
fh.write("{}\t{}\t{}\t{}\n".format(x, y, r, p)) | |
- | |
+ | |
finally : | |
if fh is not None: | |
fh.close() | |
t@@ -1546,7 +1528,7 @@ class Spherebin: | |
for (x, y, r) in zip(cxlist, cylist, crlist): | |
fh.write("{}\t{}\t{}\n".format(x, y, r)) | |
- | |
+ | |
finally : | |
if fh is not None: | |
fh.close() | |
t@@ -1561,7 +1543,7 @@ class Spherebin: | |
for (ax, ay, dax, day) in zip(axlist, aylist, daxlist, daylist): | |
fh.write("{}\t{}\t{}\t{}\n".format(ax, ay, dax, day)) | |
- | |
+ | |
finally : | |
if fh is not None: | |
fh.close() | |
t@@ -1576,7 +1558,7 @@ class Spherebin: | |
for (x, y, dvx, dvy) in zip(xlist, ylist, dvxlist, dvylist): | |
fh.write("{}\t{}\t{}\t{}\n".format(x, y, dvx, dvy)) | |
- | |
+ | |
finally : | |
if fh is not None: | |
fh.close() | |
t@@ -1652,7 +1634,7 @@ class Spherebin: | |
for (sx, sy, dsx, dsy) in zip(sxlist, sylist, dsxlist, dsylist): | |
fh.write("{}\t{}\t{}\t{}\n".format(sx, sy, dsx, dsy)) | |
- | |
+ | |
finally : | |
if fh is not None: | |
fh.close() | |
t@@ -2033,7 +2015,7 @@ def visualize(project, method = 'energy', savefig = True… | |
ax2.plot(xdisp/w_x0, dilation, '+-') | |
ax2.grid() | |
- else : | |
+ else : | |
# Write values to textfile | |
filename = "shear-stresses-{0}.txt".format(project) | |
#print("Writing stress data to " + filename) | |
t@@ -2075,7 +2057,7 @@ def run(binary, verbose=True, hideinputfile=False): | |
subprocess.call("cd ..; ./sphere " + quiet + " " + binary + " " + stdout, … | |
def torqueScriptParallel3(obj1, obj2, obj3, | |
- email="[email protected]", | |
+ email="[email protected]", | |
email_alerts="ae", | |
walltime="24:00:00", | |
queue="qfermi", | |
t@@ -2124,7 +2106,7 @@ def torqueScriptParallel3(obj1, obj2, obj3, | |
def torqueScriptSerial3(obj1, obj2, obj3, | |
- email="[email protected]", | |
+ email="[email protected]", | |
email_alerts="ae", | |
walltime="24:00:00", | |
queue="qfermi", | |
t@@ -2172,7 +2154,7 @@ def status(project): | |
""" Check the status.dat file for the target project, | |
and return the last file numer. | |
""" | |
- | |
+ | |
fh = None | |
try : | |
filepath = "../output/{0}.status.dat".format(project) |