@@ -173,7 +173,8 @@ def _initializeSampleGeometryMemory(self):
173173 self .Radii = np .array (self .Radii )
174174 vf = 4 / 3 * np .pi * np .sum ([rad ** 3 for rad in self .Radii ])/ (self .lx * self .ly * self .lz )
175175 if self .flVerbose :
176- print (f"Placed a total of { len (self .Radii )} spheres, resulting in a final volume fraction of { vf } " )
176+ print (f"Placed a total of { len (self .Radii )} spheres, resulting in a final volume fraction of { vf } " )
177+
177178 # sample what material in each sphere according to user specified average material abundance in spheres
178179 self .MatInds = []
179180 for _ in range (0 ,len (self .Radii )):
@@ -235,43 +236,45 @@ def _generateRandomPointFastRSA(self, radius):
235236
236237 #Select a random point within the cell
237238 if self .xperiodic :
238- if xhi > self .xbounds [1 ]:
239- xhi = self .xbounds [1 ]
239+ if xhi > self .xbounds [1 ]: xhi = self .xbounds [1 ]
240240 else :
241- if ix == 0 :
242- xlo = xlo + radius
243- if ix == self .nbinx - 1 :
244- xhi = self .xbounds [1 ] - radius
241+ if ix == 0 : xlo = xlo + radius
242+ if ix == self .nbinx - 1 : xhi = self .xbounds [1 ] - radius
245243 x = self .Rng .uniform (xlo , xhi )
246244
247245 if self .yperiodic :
248- if yhi > self .ybounds [1 ]:
249- yhi = self .ybounds [1 ]
246+ if yhi > self .ybounds [1 ]: yhi = self .ybounds [1 ]
250247 else :
251- if iy == 0 :
252- ylo = ylo + radius
253- if iy == self .nbiny - 1 :
254- yhi = self .ybounds [1 ] - radius
248+ if iy == 0 : ylo = ylo + radius
249+ if iy == self .nbiny - 1 : yhi = self .ybounds [1 ] - radius
255250 y = self .Rng .uniform (ylo , yhi )
256251
257252 if self .zperiodic :
258- if zhi > self .zbounds [1 ]:
259- zhi = self .zbounds [1 ]
253+ if zhi > self .zbounds [1 ]: zhi = self .zbounds [1 ]
260254 else :
261- if iz == 0 :
262- zlo = zlo + radius
263- if iz == self .nbinz - 1 :
264- zhi = self .zbounds [1 ] - radius
255+ if iz == 0 : zlo = zlo + radius
256+ if iz == self .nbinz - 1 : zhi = self .zbounds [1 ] - radius
265257 z = self .Rng .uniform (zlo , zhi )
266258
267259 return x , y , z
268260
269261
270262 ## \brief Returns material at specified location
271263 #
264+ # Distance calculation used with periodic boundaries uses the minimum image convention
265+ #
272266 # \returns material type of location
273267 def _samplePointNoGrid (self ):
274- distances = np .sqrt ( (self .Centers [:,0 ]- self .Part .x )** 2 + (self .Centers [:,1 ]- self .Part .y )** 2 + (self .Centers [:,2 ]- self .Part .z )** 2 )
268+ dx = self .Centers [:,0 ]- self .Part .x
269+ if self .xperiodic : dx = dx - np .int32 (2 * dx / self .lx )* self .lx
270+
271+ dy = self .Centers [:,1 ]- self .Part .y
272+ if self .yperiodic : dy = dy - np .int32 (2 * dy / self .ly )* self .ly
273+
274+ dz = self .Centers [:,2 ]- self .Part .z
275+ if self .zperiodic : dz = dz - np .int32 (2 * dz / self .lz )* self .lz
276+
277+ distances = np .sqrt (dx ** 2 + dy ** 2 + dz ** 2 )
275278 overlapIndices = np .where (self .Radii > distances )[0 ]
276279 if len (overlapIndices ) > 0 : self .CurrentMatInd = self .MatInds [overlapIndices [0 ]]
277280 else : self .CurrentMatInd = self .matMatrix
@@ -287,7 +290,7 @@ def _samplePointGrid(self):
287290
288291 ## \brief Adds sphere to bins that it could potentially overlap
289292 #
290- # This is specific to FastRSA, potentially taking advantage of the case where radius is constant
293+ # This is specific to FastRSA, taking advantage of the radius being constant
291294 # by adding the sphere to a single bin.
292295 #
293296 # \param[in] x, y, x, float; coordinates of sphere center
@@ -300,7 +303,8 @@ def _addSphereToBinsFastRSA(self, x, y, z, rad, index):
300303 iz = int ((z - self .zbounds [0 ]) / self .gridSize )
301304 gridIndex = self .cellCoordsToIndex [(ix ,iy ,iz )]
302305 self .grid [ix , iy , iz ] = [[x , y , z , rad , index ]]
303- self .emptyCellList = np .delete (self .emptyCellList , self .emptyCellList == gridIndex )
306+ self .emptyCellList = np .delete (self .emptyCellList , self .emptyCellList == gridIndex )
307+
304308
305309 ## \brief Adds sphere to bins that it could potentially overlap
306310 #
@@ -326,20 +330,25 @@ def _addSphereToBinsGrid(self, x0, y0, z0, rad, index):
326330 z = z0 - self .zbounds [0 ]
327331 maxOverlapDistance = rad + self .radMax
328332
329- #Bin extents in x
333+ #Sphere is added to all grid cells where overlaps need to be checked.
334+ #ixlo/ixhi, iylo/iyhi, izlo/izhi are the extents of the grid subdomain,
335+ #as grid indices. Negative values of ixlo,iylo,izlo will be used to wrap
336+ #around periodic boundaries, if applicable
337+
338+ #Grid subdomain extents in x
330339 ixlo = int ((x - maxOverlapDistance )/ self .gridSize )- 1
331- if x < maxOverlapDistance :
332- ixlo = - 1
340+ if x < maxOverlapDistance : #Needed due to potential truncation of grid cell at upper domain boundary
341+ ixlo -= 1
333342 ixhi = int ((x + maxOverlapDistance )/ self .gridSize )+ 1
334343 if ixlo < 0 and not self .xperiodic :
335344 ixlo = 0
336345 if ixhi >= self .nbinx and not self .xperiodic :
337346 ixhi = self .nbinx - 1
338347
339- #Bin extents in y
348+ #Grid subdomain extens in y
340349 iylo = int ((y - maxOverlapDistance )/ self .gridSize )- 1
341350 if y < maxOverlapDistance :
342- iylo = - 1
351+ iylo -= 1
343352 iyhi = int ((y + maxOverlapDistance )/ self .gridSize )+ 1
344353 if iylo < 0 and not self .yperiodic :
345354 iylo = 0
@@ -349,7 +358,7 @@ def _addSphereToBinsGrid(self, x0, y0, z0, rad, index):
349358 #Bin extents in z
350359 izlo = int ((z - maxOverlapDistance )/ self .gridSize )- 1
351360 if z < maxOverlapDistance :
352- izlo = - 1
361+ izlo -= 1
353362 izhi = int ((z + maxOverlapDistance )/ self .gridSize )+ 1
354363 if izlo < 0 and not self .zperiodic :
355364 izlo = 0
@@ -367,6 +376,7 @@ def _addSphereToBinsGrid(self, x0, y0, z0, rad, index):
367376 yc = (iiy + 0.5 )* self .gridSize
368377 zc = (iiz + 0.5 )* self .gridSize
369378 if (xs - xc )* (xs - xc ) + (ys - yc )* (ys - yc ) + (zs - zc )* (zs - zc ) < (maxOverlapDistance + self .bindiag )* (maxOverlapDistance + self .bindiag ):
379+ #If sphere is within relevant distance of grid cell center, add sphere to grid cell
370380 if self .grid [iix , iiy , iiz ] is None :
371381 self .grid [iix , iiy , iiz ] = []
372382 self .grid [iix , iiy , iiz ].append ([xs + self .xbounds [0 ],
@@ -380,14 +390,24 @@ def _addSphereToBinsGrid(self, x0, y0, z0, rad, index):
380390 ## \brief Check if a given sphere overlaps any existing spheres
381391 #
382392 # Checks all possible pairs of spheres, hence scaling is N^2
393+ # Distance calculation used with periodic boundaries uses the minimum image convention
383394 #
384395 # \param[in] x, y, x, float; coordinates of sphere center
385396 # \param[in] rad, float: sphere radius
386397 # \returns Index of sphere that is overlapped; -1 if no overlap
387398 def _checkSphereOverlapNoGrid (self , x , y , z , rad ):
388399 if len (self .Centers ) == 0 : return - 1
389400 centers = np .array (self .Centers )
390- distances = np .sqrt ( (centers [:,0 ]- x )** 2 + (centers [:,1 ]- y )** 2 + (centers [:,2 ]- z )** 2 )
401+ dx = centers [:,0 ]- x
402+ if self .xperiodic : dx = dx - np .int32 (2 * dx / self .lx )* self .lx
403+
404+ dy = centers [:,1 ]- y
405+ if self .yperiodic : dy = dy - np .int32 (2 * dy / self .ly )* self .ly
406+
407+ dz = centers [:,2 ]- z
408+ if self .zperiodic : dz = dz - np .int32 (2 * dz / self .lz )* self .lz
409+
410+ distances = np .sqrt (dx ** 2 + dy ** 2 + dz ** 2 )
391411 overlapIndices = distances < self .Radii + rad
392412 if np .any (overlapIndices ): return np .where (overlapIndices )[0 ][0 ]
393413 else : return - 1
@@ -399,48 +419,58 @@ def _checkSphereOverlapNoGrid(self, x, y, z, rad):
399419 # to the fast RSA method, where only the nearest neighboring bins need to be
400420 # checked.
401421 #
402- # \param[in] x, y, z, float; coordinates of sphere center
422+ # The sphere is checked against all grid cells where overlaps could occur.
423+ # Variables ixlo/ixhi, iylo/iyhi, and izlo/izhi are the extents of the grid
424+ # subdomain where overlap checking is relevant, as grid indices.
425+ # Negative values of ixlo, iylo, and izlo will be used to wrap around
426+ # periodic boundaries, if applicable.
427+ #
428+ # \param[in] x0, y0, z0, float; coordinates of sphere
403429 # \param[in] rad, float: sphere radius
404430 # \returns Index of sphere that is overlapped; -1 if no overlap
405- def _checkSphereOverlapGridFastRSA (self , x , y , z , rad ):
406-
407- ix = int ((x - self .xbounds [0 ])// self .gridSize )
408- iy = int ((y - self .ybounds [0 ])// self .gridSize )
409- iz = int ((z - self .zbounds [0 ])// self .gridSize )
431+ def _checkSphereOverlapGridFastRSA (self , x0 , y0 , z0 , rad ):
432+ x = x0 - self .xbounds [0 ]
433+ y = y0 - self .ybounds [0 ]
434+ z = z0 - self .zbounds [0 ]
435+
436+ ix = int (x / self .gridSize )
437+ iy = int (y / self .gridSize )
438+ iz = int (z / self .gridSize )
439+
410440
411441 ixlo = ix - self .fastRSANumGridCheck
412- ixhi = ix + self .fastRSANumGridCheck
413- if ixlo < 0 and not self . xperiodic :
414- ixlo = 0
415- if ixhi >= self . nbinx and not self . xperiodic :
416- ixhi = self .nbinx - 1
442+ ixhi = ix + self .fastRSANumGridCheck
443+ if self . xperiodic : ixlo -= 1
444+ else :
445+ if ixlo < 0 : ixlo = 0
446+ if ixhi >= self . nbinx : ixhi = self .nbinx - 1
417447
418448 iylo = iy - self .fastRSANumGridCheck
419449 iyhi = iy + self .fastRSANumGridCheck
420- if iylo < 0 and not self . yperiodic :
421- iylo = 0
422- if iyhi >= self . nbiny and not self . yperiodic :
423- iyhi = self .nbiny - 1
450+ if self . yperiodic : iylo -= 1
451+ else :
452+ if iylo < 0 : iylo = 0
453+ if iyhi >= self . nbiny : iyhi = self .nbiny - 1
424454
425455 izlo = iz - self .fastRSANumGridCheck
426456 izhi = iz + self .fastRSANumGridCheck
427- if izlo < 0 and not self . zperiodic :
428- izlo = 0
429- if izhi >= self . nbinz and not self . zperiodic :
430- izhi = self .nbinz - 1
457+ if self . zperiodic : izlo -= 1
458+ else :
459+ if izlo < 0 : izlo = 0
460+ if izhi >= self . nbinz : izhi = self .nbinz - 1
431461
432462 for ix in np .arange (ixlo , ixhi + 1 ):
433- iix , xs = self ._wrap_bins (ix , x , self .nbinx , self .lx , self .xperiodic )
463+ iix , xs = self ._wrap_bins (ix , x0 , self .nbinx , self .lx , self .xperiodic )
434464 for iy in np .arange (iylo , iyhi + 1 ):
435- iiy , ys = self ._wrap_bins (iy , y , self .nbiny , self .ly , self .yperiodic )
465+ iiy , ys = self ._wrap_bins (iy , y0 , self .nbiny , self .ly , self .yperiodic )
436466 for iz in np .arange (izlo , izhi + 1 ):
437- iiz , zs = self ._wrap_bins (iz , z , self .nbinz , self .lz , self .zperiodic )
438- bin = self .grid [iix , iiy , iiz ]
467+ iiz , zs = self ._wrap_bins (iz , z0 , self .nbinz , self .lz , self .zperiodic )
468+ bin = self .grid [iix , iiy , iiz ]
439469 if bin is None :
440470 continue
441471 for particle in bin :
442472 px , py , pz , prad , index = particle
443- rx = xs - px
473+ rx = xs - px
444474 ry = ys - py
445475 rz = zs - pz
446476 r2 = np .sqrt (rx * rx + ry * ry + rz * rz )
@@ -468,23 +498,16 @@ def _checkSphereOverlapGrid(self, x, y, z, rad):
468498 for particle in bin :
469499 px , py , pz , prad , index = particle
470500 rx = x - px
471- if (self .xperiodic ):
472- rx = rx - int (rx / self .lx )* self .lx
473501 ry = y - py
474- if (self .yperiodic ):
475- ry = ry - int (ry / self .ly )* self .ly
476- rz = z - pz
477- if (self .zperiodic ):
478- rz = rz - int (rz / self .lz )* self .lz
479-
502+ rz = z - pz
480503 r2 = np .sqrt (rx * rx + ry * ry + rz * rz )
481504 if r2 < rad + prad :
482505 return index
483506 return - 1
484507
485508 ## \brief Wrap bin index and sphere coordinates around periodic boundaries
486509 #
487- # Helper function for wrapping bins and sphere coordinates around PBCs
510+ # Helper function for wrapping bins and sphere coordinates around periodic boundaries
488511 #
489512 # \param[in] ibin, int; index of bin along relevant direction
490513 # \param[in] coord, float; coordinate of sphere along relevant direction
@@ -498,7 +521,7 @@ def _wrap_bins(self, ibin, coord, nbins, length, periodic):
498521 if ibin < 0 :
499522 wbin = np .max ((nbins + ibin , 0 ))
500523 wcoord = coord + length
501- if ibin >= nbins :
524+ elif ibin >= nbins :
502525 wbin = np .min ((ibin - nbins , nbins - 1 ))
503526 wcoord = coord - length
504527 else :
0 commit comments