clearly distinguish seeds for tessellation and seeds for RNG

This commit is contained in:
Martin Diehl 2020-11-15 13:06:26 +01:00
parent 1541ac0add
commit fd8743af5e
7 changed files with 62 additions and 33 deletions

View File

@ -1233,6 +1233,7 @@ class Orientation(Rotation):
array([[ 0.000, 0.000, 0.000], array([[ 0.000, 0.000, 0.000],
[ 0.577, -0.000, 0.816], [ 0.577, -0.000, 0.816],
[ 0.000, 0.000, 0.000]]) [ 0.000, 0.000, 0.000]])
""" """
d = self.to_frame(uvw=self.kinematics[mode]['direction'],with_symmetry=False) d = self.to_frame(uvw=self.kinematics[mode]['direction'],with_symmetry=False)
p = self.to_frame(hkl=self.kinematics[mode]['plane'] ,with_symmetry=False) p = self.to_frame(hkl=self.kinematics[mode]['plane'] ,with_symmetry=False)

View File

@ -682,7 +682,7 @@ class Rotation:
@staticmethod @staticmethod
def from_random(shape = None, def from_random(shape = None,
seed = None, rng_seed = None,
**kwargs): **kwargs):
""" """
Draw random rotation. Draw random rotation.
@ -694,12 +694,12 @@ class Rotation:
shape : tuple of ints, optional shape : tuple of ints, optional
Shape of the sample. Defaults to None which gives a Shape of the sample. Defaults to None which gives a
single rotation single rotation
seed : {None, int, array_like[ints], SeedSequence, BitGenerator, Generator}, optional rng_seed : {None, int, array_like[ints], SeedSequence, BitGenerator, Generator}, optional
A seed to initialize the BitGenerator. Defaults to None. A seed to initialize the BitGenerator. Defaults to None.
If None, then fresh, unpredictable entropy will be pulled from the OS. If None, then fresh, unpredictable entropy will be pulled from the OS.
""" """
rng = np.random.default_rng(seed) rng = np.random.default_rng(rng_seed)
r = rng.random(3 if shape is None else tuple(shape)+(3,) if hasattr(shape, '__iter__') else (shape,3)) r = rng.random(3 if shape is None else tuple(shape)+(3,) if hasattr(shape, '__iter__') else (shape,3))
A = np.sqrt(r[...,2]) A = np.sqrt(r[...,2])
@ -718,7 +718,7 @@ class Rotation:
N = 500, N = 500,
degrees = True, degrees = True,
fractions = True, fractions = True,
seed = None, rng_seed = None,
**kwargs): **kwargs):
""" """
Sample discrete values from a binned ODF. Sample discrete values from a binned ODF.
@ -737,7 +737,7 @@ class Rotation:
fractions : boolean, optional fractions : boolean, optional
ODF values correspond to volume fractions, not probability density. ODF values correspond to volume fractions, not probability density.
Defaults to True. Defaults to True.
seed: {None, int, array_like[ints], SeedSequence, BitGenerator, Generator}, optional rng_seed: {None, int, array_like[ints], SeedSequence, BitGenerator, Generator}, optional
A seed to initialize the BitGenerator. Defaults to None, i.e. unpredictable entropy A seed to initialize the BitGenerator. Defaults to None, i.e. unpredictable entropy
will be pulled from the OS. will be pulled from the OS.
@ -768,7 +768,7 @@ class Rotation:
dg = 1.0 if fractions else _dg(Eulers,degrees) dg = 1.0 if fractions else _dg(Eulers,degrees)
dV_V = dg * np.maximum(0.0,weights.squeeze()) dV_V = dg * np.maximum(0.0,weights.squeeze())
return Rotation.from_Eulers(Eulers[util.hybrid_IA(dV_V,N,seed)],degrees) return Rotation.from_Eulers(Eulers[util.hybrid_IA(dV_V,N,rng_seed)],degrees)
@staticmethod @staticmethod
@ -776,7 +776,7 @@ class Rotation:
sigma, sigma,
N = 500, N = 500,
degrees = True, degrees = True,
seed = None, rng_seed = None,
**kwargs): **kwargs):
""" """
Calculate set of rotations with Gaussian distribution around center. Calculate set of rotations with Gaussian distribution around center.
@ -791,12 +791,12 @@ class Rotation:
Number of samples, defaults to 500. Number of samples, defaults to 500.
degrees : boolean, optional degrees : boolean, optional
sigma is given in degrees. sigma is given in degrees.
seed : {None, int, array_like[ints], SeedSequence, BitGenerator, Generator}, optional rng_seed : {None, int, array_like[ints], SeedSequence, BitGenerator, Generator}, optional
A seed to initialize the BitGenerator. Defaults to None, i.e. unpredictable entropy A seed to initialize the BitGenerator. Defaults to None, i.e. unpredictable entropy
will be pulled from the OS. will be pulled from the OS.
""" """
rng = np.random.default_rng(seed) rng = np.random.default_rng(rng_seed)
sigma = np.radians(sigma) if degrees else sigma sigma = np.radians(sigma) if degrees else sigma
u,Theta = (rng.random((N,2)) * 2.0 * np.array([1,np.pi]) - np.array([1.0, 0])).T u,Theta = (rng.random((N,2)) * 2.0 * np.array([1,np.pi]) - np.array([1.0, 0])).T
omega = abs(rng.normal(scale=sigma,size=N)) omega = abs(rng.normal(scale=sigma,size=N))
@ -813,7 +813,7 @@ class Rotation:
sigma = 0.0, sigma = 0.0,
N = 500, N = 500,
degrees = True, degrees = True,
seed = None, rng_seed = None,
**kwargs): **kwargs):
""" """
Calculate set of rotations with Gaussian distribution around direction. Calculate set of rotations with Gaussian distribution around direction.
@ -831,12 +831,12 @@ class Rotation:
Number of samples, defaults to 500. Number of samples, defaults to 500.
degrees : boolean, optional degrees : boolean, optional
sigma, alpha, and beta are given in degrees. sigma, alpha, and beta are given in degrees.
seed : {None, int, array_like[ints], SeedSequence, BitGenerator, Generator}, optional rng_seed : {None, int, array_like[ints], SeedSequence, BitGenerator, Generator}, optional
A seed to initialize the BitGenerator. Defaults to None, i.e. unpredictable entropy A seed to initialize the BitGenerator. Defaults to None, i.e. unpredictable entropy
will be pulled from the OS. will be pulled from the OS.
""" """
rng = np.random.default_rng(seed) rng = np.random.default_rng(rng_seed)
sigma_,alpha_,beta_ = map(np.radians,(sigma,alpha,beta)) if degrees else (sigma,alpha,beta) sigma_,alpha_,beta_ = map(np.radians,(sigma,alpha,beta)) if degrees else (sigma,alpha,beta)
d_cr = np.array([np.sin(alpha_[0])*np.cos(alpha_[1]), np.sin(alpha_[0])*np.sin(alpha_[1]), np.cos(alpha_[0])]) d_cr = np.array([np.sin(alpha_[0])*np.cos(alpha_[1]), np.sin(alpha_[0])*np.sin(alpha_[1]), np.cos(alpha_[0])])

View File

@ -5,7 +5,7 @@ from . import util
from . import grid_filters from . import grid_filters
def from_random(size,N_seeds,grid=None,seed=None): def from_random(size,N_seeds,grid=None,rng_seed=None):
""" """
Random seeding in space. Random seeding in space.
@ -18,12 +18,12 @@ def from_random(size,N_seeds,grid=None,seed=None):
grid : numpy.ndarray of shape (3), optional. grid : numpy.ndarray of shape (3), optional.
If given, ensures that all seeds initiate one grain if using a If given, ensures that all seeds initiate one grain if using a
standard Voronoi tessellation. standard Voronoi tessellation.
seed : {None, int, array_like[ints], SeedSequence, BitGenerator, Generator}, optional rng_seed : {None, int, array_like[ints], SeedSequence, BitGenerator, Generator}, optional
A seed to initialize the BitGenerator. Defaults to None. A seed to initialize the BitGenerator. Defaults to None.
If None, then fresh, unpredictable entropy will be pulled from the OS. If None, then fresh, unpredictable entropy will be pulled from the OS.
""" """
rng = _np.random.default_rng(seed) rng = _np.random.default_rng(rng_seed)
if grid is None: if grid is None:
coords = rng.random((N_seeds,3)) * size coords = rng.random((N_seeds,3)) * size
else: else:
@ -34,7 +34,7 @@ def from_random(size,N_seeds,grid=None,seed=None):
return coords return coords
def from_Poisson_disc(size,N_seeds,N_candidates,distance,periodic=True,seed=None): def from_Poisson_disc(size,N_seeds,N_candidates,distance,periodic=True,rng_seed=None):
""" """
Seeding in space according to a Poisson disc distribution. Seeding in space according to a Poisson disc distribution.
@ -50,12 +50,12 @@ def from_Poisson_disc(size,N_seeds,N_candidates,distance,periodic=True,seed=None
Minimum acceptable distance to other seeds. Minimum acceptable distance to other seeds.
periodic : boolean, optional periodic : boolean, optional
Calculate minimum distance for periodically repeated grid. Calculate minimum distance for periodically repeated grid.
seed : {None, int, array_like[ints], SeedSequence, BitGenerator, Generator}, optional rng_seed : {None, int, array_like[ints], SeedSequence, BitGenerator, Generator}, optional
A seed to initialize the BitGenerator. Defaults to None. A seed to initialize the BitGenerator. Defaults to None.
If None, then fresh, unpredictable entropy will be pulled from the OS. If None, then fresh, unpredictable entropy will be pulled from the OS.
""" """
rng = _np.random.default_rng(seed) rng = _np.random.default_rng(rng_seed)
coords = _np.empty((N_seeds,3)) coords = _np.empty((N_seeds,3))
coords[0] = rng.random(3) * size coords[0] = rng.random(3) * size

View File

@ -42,7 +42,7 @@ def srepr(arg,glue = '\n'):
arg : iterable arg : iterable
Items to join. Items to join.
glue : str, optional glue : str, optional
Defaults to \n. Glue used for joining operation. Defaults to \n.
""" """
if (not hasattr(arg, "strip") and if (not hasattr(arg, "strip") and
@ -163,7 +163,15 @@ def show_progress(iterable,N_iter=None,prefix='',bar_length=50):
def scale_to_coprime(v): def scale_to_coprime(v):
"""Scale vector to co-prime (relatively prime) integers.""" """
Scale vector to co-prime (relatively prime) integers.
Parameters
----------
v : numpy.ndarray of shape (:)
Vector to scale.
"""
MAX_DENOMINATOR = 1000000 MAX_DENOMINATOR = 1000000
def get_square_denominator(x): def get_square_denominator(x):
@ -214,7 +222,21 @@ def execution_stamp(class_name,function_name=None):
return f'damask.{class_name}{_function_name} v{version} ({now})' return f'damask.{class_name}{_function_name} v{version} ({now})'
def hybrid_IA(dist,N,seed=None): def hybrid_IA(dist,N,rng_seed=None):
"""
Hybrid integer approximation.
Parameters
----------
dist : numpy.ndarray
Distribution to be approximated
N : int
Number of samples to draw.
rng_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.
"""
N_opt_samples,N_inv_samples = (max(np.count_nonzero(dist),N),0) # random subsampling if too little samples requested N_opt_samples,N_inv_samples = (max(np.count_nonzero(dist),N),0) # random subsampling if too little samples requested
scale_,scale,inc_factor = (0.0,float(N_opt_samples),1.0) scale_,scale,inc_factor = (0.0,float(N_opt_samples),1.0)
@ -225,7 +247,7 @@ def hybrid_IA(dist,N,seed=None):
if N_inv_samples < N_opt_samples else \ if N_inv_samples < N_opt_samples else \
(scale_,0.5*(scale_ + scale), 1.0) (scale_,0.5*(scale_ + scale), 1.0)
return np.repeat(np.arange(len(dist)),repeats)[np.random.default_rng(seed).permutation(N_inv_samples)[:N]] return np.repeat(np.arange(len(dist)),repeats)[np.random.default_rng(rng_seed).permutation(N_inv_samples)[:N]]
def shapeshifter(fro,to,mode='left',keep_ones=False): def shapeshifter(fro,to,mode='left',keep_ones=False):

View File

@ -18,6 +18,7 @@ def patch_damask_version(monkeypatch):
"""Set damask.version for reproducible tests results.""" """Set damask.version for reproducible tests results."""
monkeypatch.setattr(damask, 'version', patched_version) monkeypatch.setattr(damask, 'version', patched_version)
patched_date = datetime.datetime(2019, 11, 2, 11, 58, 0) patched_date = datetime.datetime(2019, 11, 2, 11, 58, 0)
@pytest.fixture @pytest.fixture
def patch_datetime_now(monkeypatch): def patch_datetime_now(monkeypatch):
@ -29,6 +30,7 @@ def patch_datetime_now(monkeypatch):
monkeypatch.setattr(datetime, 'datetime', mydatetime) monkeypatch.setattr(datetime, 'datetime', mydatetime)
@pytest.fixture @pytest.fixture
def patch_execution_stamp(monkeypatch): def patch_execution_stamp(monkeypatch):
"""Set damask.util.execution_stamp for reproducible tests results.""" """Set damask.util.execution_stamp for reproducible tests results."""
@ -38,6 +40,7 @@ def patch_execution_stamp(monkeypatch):
monkeypatch.setattr(damask.util, 'execution_stamp', execution_stamp) monkeypatch.setattr(damask.util, 'execution_stamp', execution_stamp)
@pytest.fixture @pytest.fixture
def patch_plt_show(monkeypatch): def patch_plt_show(monkeypatch):
def _None(block=None): def _None(block=None):
@ -50,16 +53,19 @@ def pytest_addoption(parser):
action="store_true", action="store_true",
default=False) default=False)
@pytest.fixture @pytest.fixture
def update(request): def update(request):
"""Store current results as new reference results.""" """Store current results as new reference results."""
return request.config.getoption("--update") return request.config.getoption("--update")
@pytest.fixture @pytest.fixture
def reference_dir_base(): def reference_dir_base():
"""Directory containing reference results.""" """Directory containing reference results."""
return Path(__file__).parent/'reference' return Path(__file__).parent/'reference'
@pytest.fixture @pytest.fixture
def set_of_quaternions(): def set_of_quaternions():
"""A set of n random rotations.""" """A set of n random rotations."""

View File

@ -125,9 +125,9 @@ class TestOrientation:
def test_from_fiber_component(self): def test_from_fiber_component(self):
r = Rotation.from_fiber_component(alpha=np.zeros(2),beta=np.zeros(2), r = Rotation.from_fiber_component(alpha=np.zeros(2),beta=np.zeros(2),
sigma=0.0,N=1,seed=0) sigma=0.0,N=1,rng_seed=0)
assert np.all(Orientation.from_fiber_component(alpha=np.zeros(2),beta=np.zeros(2), assert np.all(Orientation.from_fiber_component(alpha=np.zeros(2),beta=np.zeros(2),
sigma=0.0,N=1,seed=0,lattice='triclinic').quaternion sigma=0.0,N=1,rng_seed=0,lattice='triclinic').quaternion
== r.quaternion) == r.quaternion)
@pytest.mark.parametrize('kwargs',[ @pytest.mark.parametrize('kwargs',[
@ -175,8 +175,8 @@ class TestOrientation:
@pytest.mark.parametrize('lattice',Orientation.crystal_families) @pytest.mark.parametrize('lattice',Orientation.crystal_families)
@pytest.mark.parametrize('N',[1,8,32]) @pytest.mark.parametrize('N',[1,8,32])
def test_disorientation(self,lattice,N): def test_disorientation(self,lattice,N):
o = Orientation.from_random(lattice=lattice,shape=N,seed=0) o = Orientation.from_random(lattice=lattice,shape=N)
p = Orientation.from_random(lattice=lattice,shape=N,seed=1) p = Orientation.from_random(lattice=lattice,shape=N)
d,ops = o.disorientation(p,return_operators=True) d,ops = o.disorientation(p,return_operators=True)
@ -198,8 +198,8 @@ class TestOrientation:
(None,None), (None,None),
]) ])
def test_disorientation_blending(self,lattice,a,b): def test_disorientation_blending(self,lattice,a,b):
o = Orientation.from_random(lattice=lattice,shape=a,seed=0) o = Orientation.from_random(lattice=lattice,shape=a)
p = Orientation.from_random(lattice=lattice,shape=b,seed=1) p = Orientation.from_random(lattice=lattice,shape=b)
blend = util.shapeblender(o.shape,p.shape) blend = util.shapeblender(o.shape,p.shape)
for loc in np.random.randint(0,blend,(10,len(blend))): for loc in np.random.randint(0,blend,(10,len(blend))):
assert o[tuple(loc[:len(o.shape)])].disorientation(p[tuple(loc[-len(p.shape):])]) \ assert o[tuple(loc[:len(o.shape)])].disorientation(p[tuple(loc[-len(p.shape):])]) \
@ -214,7 +214,7 @@ class TestOrientation:
@pytest.mark.parametrize('lattice',Orientation.crystal_families) @pytest.mark.parametrize('lattice',Orientation.crystal_families)
@pytest.mark.parametrize('shape',[(1),(2,3),(4,3,2)]) @pytest.mark.parametrize('shape',[(1),(2,3),(4,3,2)])
def test_reduced_vectorization(self,lattice,shape): def test_reduced_vectorization(self,lattice,shape):
o = Orientation.from_random(lattice=lattice,shape=shape,seed=0) o = Orientation.from_random(lattice=lattice,shape=shape)
for r, theO in zip(o.reduced.flatten(),o.flatten()): for r, theO in zip(o.reduced.flatten(),o.flatten()):
assert r == theO.reduced assert r == theO.reduced
@ -223,7 +223,7 @@ class TestOrientation:
@pytest.mark.parametrize('vector',np.array([[1,0,0],[1,2,3],[-1,1,-1]])) @pytest.mark.parametrize('vector',np.array([[1,0,0],[1,2,3],[-1,1,-1]]))
@pytest.mark.parametrize('proper',[True,False]) @pytest.mark.parametrize('proper',[True,False])
def test_to_SST_vectorization(self,lattice,shape,vector,proper): def test_to_SST_vectorization(self,lattice,shape,vector,proper):
o = Orientation.from_random(lattice=lattice,shape=shape,seed=0) o = Orientation.from_random(lattice=lattice,shape=shape)
for r, theO in zip(o.to_SST(vector=vector,proper=proper).reshape((-1,3)),o.flatten()): for r, theO in zip(o.to_SST(vector=vector,proper=proper).reshape((-1,3)),o.flatten()):
assert np.allclose(r,theO.to_SST(vector=vector,proper=proper)) assert np.allclose(r,theO.to_SST(vector=vector,proper=proper))
@ -232,7 +232,7 @@ class TestOrientation:
@pytest.mark.parametrize('vector',np.array([[1,0,0],[1,2,3],[-1,1,-1]])) @pytest.mark.parametrize('vector',np.array([[1,0,0],[1,2,3],[-1,1,-1]]))
@pytest.mark.parametrize('proper',[True,False]) @pytest.mark.parametrize('proper',[True,False])
def test_IPF_color_vectorization(self,lattice,shape,vector,proper): def test_IPF_color_vectorization(self,lattice,shape,vector,proper):
o = Orientation.from_random(lattice=lattice,shape=shape,seed=0) o = Orientation.from_random(lattice=lattice,shape=shape)
poles = o.to_SST(vector=vector,proper=proper) poles = o.to_SST(vector=vector,proper=proper)
for r, theO in zip(o.IPF_color(poles,proper=proper).reshape((-1,3)),o.flatten()): for r, theO in zip(o.IPF_color(poles,proper=proper).reshape((-1,3)),o.flatten()):
assert np.allclose(r,theO.IPF_color(theO.to_SST(vector=vector,proper=proper),proper=proper)) assert np.allclose(r,theO.IPF_color(theO.to_SST(vector=vector,proper=proper),proper=proper))
@ -245,7 +245,7 @@ class TestOrientation:
(None,(3,)), (None,(3,)),
]) ])
def test_to_SST_blending(self,lattice,a,b): def test_to_SST_blending(self,lattice,a,b):
o = Orientation.from_random(lattice=lattice,shape=a,seed=0) o = Orientation.from_random(lattice=lattice,shape=a)
v = np.random.random(b+(3,)) v = np.random.random(b+(3,))
blend = util.shapeblender(o.shape,b) blend = util.shapeblender(o.shape,b)
for loc in np.random.randint(0,blend,(10,len(blend))): for loc in np.random.randint(0,blend,(10,len(blend))):

View File

@ -778,7 +778,7 @@ class TestRotation:
assert r.shape == shape assert r.shape == shape
def test_equal(self): def test_equal(self):
assert Rotation.from_random(seed=1) == Rotation.from_random(seed=1) assert Rotation.from_random(rng_seed=1) == Rotation.from_random(rng_seed=1)
def test_inversion(self): def test_inversion(self):
r = Rotation.from_random() r = Rotation.from_random()