Poisson disc for periodic situation

This commit is contained in:
Martin Diehl 2020-09-24 21:26:16 +02:00
parent ec23ab8b61
commit e5b414419a
2 changed files with 17 additions and 12 deletions

View File

@ -8,7 +8,7 @@ from . import grid_filters
def from_random(size,N_seeds,grid=None,seed=None):
"""
Random seeding in space.
Parameters
----------
size : numpy.ndarray of shape (3)
@ -21,7 +21,7 @@ def from_random(size,N_seeds,grid=None,seed=None):
seed : {None, int, array_like[ints], SeedSequence, BitGenerator, Generator}, optional
A seed to initialize the BitGenerator. Defaults to None.
If None, then fresh, unpredictable entropy will be pulled from the OS.
"""
rng = _np.random.default_rng(seed)
if grid is None:
@ -31,13 +31,13 @@ def from_random(size,N_seeds,grid=None,seed=None):
coords = grid_coords[rng.choice(_np.prod(grid),N_seeds, replace=False)] \
+ _np.broadcast_to(size/grid,(N_seeds,3))*(rng.random((N_seeds,3))*.5-.25) # wobble without leaving grid
coords
return coords
def from_Poisson_disc(size,N_seeds,N_candidates,distance,seed=None):
def from_Poisson_disc(size,N_seeds,N_candidates,distance,periodic=True,seed=None):
"""
Seeding in space according to a Poisson disc distribution.
Parameters
----------
size : numpy.ndarray of shape (3)
@ -48,10 +48,12 @@ def from_Poisson_disc(size,N_seeds,N_candidates,distance,seed=None):
Number of candidates to consider for finding best candidate.
distance : float
Minimum acceptable distance to other seeds.
periodic : boolean, optional
Calculate minimum distance for periodically repeated grid.
seed : {None, int, array_like[ints], SeedSequence, BitGenerator, Generator}, optional
A seed to initialize the BitGenerator. Defaults to None.
If None, then fresh, unpredictable entropy will be pulled from the OS.
"""
rng = _np.random.default_rng(seed)
coords = _np.empty((N_seeds,3))
@ -61,7 +63,8 @@ def from_Poisson_disc(size,N_seeds,N_candidates,distance,seed=None):
progress = util._ProgressBar(N_seeds+1,'',50)
while i < N_seeds:
candidates = rng.random((N_candidates,3))*_np.broadcast_to(size,(N_candidates,3))
tree = _spatial.cKDTree(coords[:i])
tree = _spatial.cKDTree(coords[:i],boxsize=size) if periodic else \
_spatial.cKDTree(coords[:i])
distances, dev_null = tree.query(candidates)
best = distances.argmax()
if distances[best] > distance: # require minimum separation
@ -75,12 +78,12 @@ def from_Poisson_disc(size,N_seeds,N_candidates,distance,seed=None):
def from_geom(geom,selection=None,invert=False):
"""
Create seed from existing geometry description.
Parameters
----------
geom : damask.Geom
...
"""
material = geom.materials.reshape((-1,1),order='F')
mask = _np.full(geom.grid.prod(),True,dtype=bool) if selection is None else \

View File

@ -13,11 +13,13 @@ class TestSeeds:
coords = seeds.from_random(size,N_seeds,grid)
assert (0<=coords).all() and (coords<size).all()
def test_from_Poisson_disc(self):
@pytest.mark.parametrize('periodic',[True,False])
def test_from_Poisson_disc(self,periodic):
N_seeds = np.random.randint(30,300)
N_candidates = N_seeds//15
distance = np.random.random()
size = np.ones(3)*distance*N_seeds
coords = seeds.from_Poisson_disc(size,N_seeds,N_candidates,distance)
min_dists, _ = cKDTree(coords).query(coords, 2)
coords = seeds.from_Poisson_disc(size,N_seeds,N_candidates,distance,periodic=periodic)
min_dists, _ = cKDTree(coords,boxsize=size).query(coords, 2) if periodic else \
cKDTree(coords).query(coords, 2)
assert (0<= coords).all() and (coords<size).all() and np.min(min_dists[:,1])>=distance