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],
[ 0.577, -0.000, 0.816],
[ 0.000, 0.000, 0.000]])
"""
d = self.to_frame(uvw=self.kinematics[mode]['direction'],with_symmetry=False)
p = self.to_frame(hkl=self.kinematics[mode]['plane'] ,with_symmetry=False)

View File

@ -682,7 +682,7 @@ class Rotation:
@staticmethod
def from_random(shape = None,
seed = None,
rng_seed = None,
**kwargs):
"""
Draw random rotation.
@ -694,12 +694,12 @@ class Rotation:
shape : tuple of ints, optional
Shape of the sample. Defaults to None which gives a
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.
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))
A = np.sqrt(r[...,2])
@ -718,7 +718,7 @@ class Rotation:
N = 500,
degrees = True,
fractions = True,
seed = None,
rng_seed = None,
**kwargs):
"""
Sample discrete values from a binned ODF.
@ -737,7 +737,7 @@ class Rotation:
fractions : boolean, optional
ODF values correspond to volume fractions, not probability density.
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
will be pulled from the OS.
@ -768,7 +768,7 @@ class Rotation:
dg = 1.0 if fractions else _dg(Eulers,degrees)
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
@ -776,7 +776,7 @@ class Rotation:
sigma,
N = 500,
degrees = True,
seed = None,
rng_seed = None,
**kwargs):
"""
Calculate set of rotations with Gaussian distribution around center.
@ -791,12 +791,12 @@ class Rotation:
Number of samples, defaults to 500.
degrees : boolean, optional
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
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
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))
@ -813,7 +813,7 @@ class Rotation:
sigma = 0.0,
N = 500,
degrees = True,
seed = None,
rng_seed = None,
**kwargs):
"""
Calculate set of rotations with Gaussian distribution around direction.
@ -831,12 +831,12 @@ class Rotation:
Number of samples, defaults to 500.
degrees : boolean, optional
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
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)
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
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.
@ -18,12 +18,12 @@ def from_random(size,N_seeds,grid=None,seed=None):
grid : numpy.ndarray of shape (3), optional.
If given, ensures that all seeds initiate one grain if using a
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.
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:
coords = rng.random((N_seeds,3)) * size
else:
@ -34,7 +34,7 @@ def from_random(size,N_seeds,grid=None,seed=None):
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.
@ -50,12 +50,12 @@ def from_Poisson_disc(size,N_seeds,N_candidates,distance,periodic=True,seed=None
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
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.
"""
rng = _np.random.default_rng(seed)
rng = _np.random.default_rng(rng_seed)
coords = _np.empty((N_seeds,3))
coords[0] = rng.random(3) * size

View File

@ -42,7 +42,7 @@ def srepr(arg,glue = '\n'):
arg : iterable
Items to join.
glue : str, optional
Defaults to \n.
Glue used for joining operation. Defaults to \n.
"""
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):
"""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
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})'
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
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 \
(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):

View File

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

View File

@ -125,9 +125,9 @@ class TestOrientation:
def test_from_fiber_component(self):
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),
sigma=0.0,N=1,seed=0,lattice='triclinic').quaternion
sigma=0.0,N=1,rng_seed=0,lattice='triclinic').quaternion
== r.quaternion)
@pytest.mark.parametrize('kwargs',[
@ -175,8 +175,8 @@ class TestOrientation:
@pytest.mark.parametrize('lattice',Orientation.crystal_families)
@pytest.mark.parametrize('N',[1,8,32])
def test_disorientation(self,lattice,N):
o = Orientation.from_random(lattice=lattice,shape=N,seed=0)
p = Orientation.from_random(lattice=lattice,shape=N,seed=1)
o = Orientation.from_random(lattice=lattice,shape=N)
p = Orientation.from_random(lattice=lattice,shape=N)
d,ops = o.disorientation(p,return_operators=True)
@ -198,8 +198,8 @@ class TestOrientation:
(None,None),
])
def test_disorientation_blending(self,lattice,a,b):
o = Orientation.from_random(lattice=lattice,shape=a,seed=0)
p = Orientation.from_random(lattice=lattice,shape=b,seed=1)
o = Orientation.from_random(lattice=lattice,shape=a)
p = Orientation.from_random(lattice=lattice,shape=b)
blend = util.shapeblender(o.shape,p.shape)
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):])]) \
@ -214,7 +214,7 @@ class TestOrientation:
@pytest.mark.parametrize('lattice',Orientation.crystal_families)
@pytest.mark.parametrize('shape',[(1),(2,3),(4,3,2)])
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()):
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('proper',[True,False])
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()):
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('proper',[True,False])
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)
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))
@ -245,7 +245,7 @@ class TestOrientation:
(None,(3,)),
])
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,))
blend = util.shapeblender(o.shape,b)
for loc in np.random.randint(0,blend,(10,len(blend))):

View File

@ -778,7 +778,7 @@ class TestRotation:
assert r.shape == shape
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):
r = Rotation.from_random()