Skip to content

Commit e4fe719

Browse files
committed
Merge branch '476-controlling-random-seed-for-tests' into 'development'
control and report random state for tests Closes #476 See merge request damask/DAMASK!1015
2 parents faf5929 + c4a64fd commit e4fe719

15 files changed

+577
-560
lines changed

python/tests/conftest.py

+13-5
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ def pytest_addoption(parser):
5353
help='Update reference results.')
5454
parser.addoption('--damaskroot',
5555
help='DAMASK root directory.')
56+
parser.addoption('--rng_entropy',
57+
help='Entropy for random seed generator.')
5658

5759
@pytest.fixture
5860
def update(pytestconfig):
@@ -81,12 +83,18 @@ def res_path_base():
8183
"""Directory containing testing resources."""
8284
return Path(__file__).parent/'resources'
8385

86+
@pytest.fixture
87+
def np_rng(pytestconfig):
88+
"""Instance of numpy.random.Generator."""
89+
e = pytestconfig.getoption('--rng_entropy')
90+
print('\nrng entropy: ',sq := np.random.SeedSequence(e if e is None else int(e)).entropy)
91+
return np.random.default_rng(seed=sq)
8492

8593
@pytest.fixture
86-
def set_of_quaternions():
94+
def set_of_quaternions(np_rng):
8795
"""A set of n random rotations."""
88-
def random_quaternions(N):
89-
r = np.random.rand(N,3)
96+
def random_quaternions(N,rng):
97+
r = np_rng.random((N,3))
9098

9199
A = np.sqrt(r[:,2])
92100
B = np.sqrt(1.0-r[:,2])
@@ -163,11 +171,11 @@ def random_quaternions(N):
163171
[1.0,-1.0,-1.0,-1.0],
164172
])
165173
specials /= np.linalg.norm(specials,axis=1).reshape(-1,1)
166-
specials_scatter = specials + np.broadcast_to((np.random.rand(4)*2.-1.)*scatter,specials.shape)
174+
specials_scatter = specials + np.broadcast_to((np_rng.random(4)*2.-1.)*scatter,specials.shape)
167175
specials_scatter /= np.linalg.norm(specials_scatter,axis=1).reshape(-1,1)
168176
specials_scatter[specials_scatter[:,0]<0]*=-1
169177

170178
return np.vstack((specials,
171179
specials_scatter,
172-
random_quaternions(n-2*len(specials)),
180+
random_quaternions(n-2*len(specials),np_rng),
173181
))

python/tests/test_Colormap.py

+12-12
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ def _patch_execution_stamp(self, patch_execution_stamp):
2323
def test_repr(self,patch_plt_show):
2424
print(Colormap.from_predefined('stress'))
2525

26-
def test_conversion(self):
26+
def test_conversion(self,np_rng):
2727
specials = np.array([[0.,0.,0.],
2828
[1.,0.,0.],
2929
[0.,1.,0.],
@@ -33,7 +33,7 @@ def test_conversion(self):
3333
[1.,0.,1.],
3434
[1.,1.,1.]
3535
])
36-
rgbs = np.vstack((specials,np.random.rand(100,3)))
36+
rgbs = np.vstack((specials,np_rng.random((100,3))))
3737
for rgb in rgbs:
3838
print('rgb',rgb)
3939

@@ -90,16 +90,16 @@ def test_from_range_types(self,low,high):
9090

9191
@pytest.mark.parametrize('format',['ASCII','paraview','GOM','gmsh'])
9292
@pytest.mark.parametrize('model',['rgb','hsv','hsl','xyz','lab','msh'])
93-
def test_from_range(self,model,format,tmp_path):
94-
N = np.random.randint(2,256)
95-
c = Colormap.from_range(np.random.rand(3),np.random.rand(3),model=model,N=N) # noqa
93+
def test_from_range(self,np_rng,model,format,tmp_path):
94+
N = np_rng.integers(2,256)
95+
c = Colormap.from_range(np_rng.random(3),np_rng.random(3),model=model,N=N) # noqa
9696
eval(f'c.save_{format}(tmp_path/"color_out")')
9797

9898
@pytest.mark.parametrize('format',['ASCII','paraview','GOM','gmsh'])
9999
@pytest.mark.parametrize('name',['strain','gnuplot','Greys','PRGn','viridis'])
100-
def test_from_predefined(self,name,format,tmp_path):
101-
N = np.random.randint(2,256)
102-
c = Colormap.from_predefined(name,N) # noqa
100+
def test_from_predefined(self,np_rng,name,format,tmp_path):
101+
N = np_rng.integers(2,256)
102+
c = Colormap.from_predefined(name,N) # noqa
103103
os.chdir(tmp_path)
104104
eval(f'c.save_{format}()')
105105

@@ -109,19 +109,19 @@ def test_from_predefined(self,name,format,tmp_path):
109109
('gmsh','test.msh')
110110
])
111111
def test_write_filehandle(self,format,name,tmp_path):
112-
c = Colormap.from_predefined('Dark2') # noqa
112+
c = Colormap.from_predefined('Dark2') # noqa
113113
fname = tmp_path/name
114-
with open(fname,'w') as f: # noqa
114+
with open(fname,'w') as f: # noqa
115115
eval(f'c.save_{format}(f)')
116116
for i in range(10):
117117
if fname.exists(): return
118118
time.sleep(.5)
119119
assert False
120120

121121
@pytest.mark.parametrize('model',['rgb','hsv','hsl','lab','invalid'])
122-
def test_invalid_color(self,model):
122+
def test_invalid_color(self,np_rng,model):
123123
with pytest.raises(ValueError):
124-
c = Colormap.from_range(-2.+np.random.rand(3),np.random.rand(3),N=10,model=model) # noqa
124+
c = Colormap.from_range(-2.+np_rng.random(3),np_rng.random(3),N=10,model=model) # noqa
125125

126126
def test_reversed(self):
127127
c_1 = Colormap.from_predefined('stress')

python/tests/test_ConfigMaterial.py

+13-11
Original file line numberDiff line numberDiff line change
@@ -94,8 +94,8 @@ def test_empty_homogenization(self,res_path):
9494
material_config['homogenization'] = None
9595
assert not material_config.is_complete
9696

97-
def test_from_table(self):
98-
N = np.random.randint(3,10)
97+
def test_from_table(self,np_rng):
98+
N = np_rng.integers(3,10)
9999
a = np.vstack((np.hstack((np.arange(N),np.arange(N)[::-1])),
100100
np.zeros(N*2),np.ones(N*2),np.zeros(N*2),np.zeros(N*2),
101101
np.ones(N*2),
@@ -115,8 +115,8 @@ def test_updated_dicts(self,res_path):
115115
assert m1['phase'].get('Aluminum') is None
116116
assert m1['homogenization'].get('SX') is None
117117

118-
def test_from_table_with_constant(self):
119-
N = np.random.randint(3,10)
118+
def test_from_table_with_constant(self,np_rng):
119+
N = np_rng.integers(3,10)
120120
a = np.vstack((np.hstack((np.arange(N),np.arange(N)[::-1])),
121121
np.zeros(N*2),np.ones(N*2),np.zeros(N*2),np.zeros(N*2),
122122
np.ones(N*2),
@@ -129,28 +129,30 @@ def test_from_table_with_constant(self):
129129

130130
@pytest.mark.parametrize('N,n,kw',[
131131
(1,1,{'phase':'Gold',
132-
'O':[1,0,0,0],
132+
'O':None,
133133
'V_e':np.eye(3),
134134
'homogenization':'SX'}),
135135
(3,1,{'phase':'Gold',
136-
'O':Rotation.from_random(3),
136+
'O':3,
137137
'V_e':np.broadcast_to(np.eye(3),(3,3,3)),
138138
'homogenization':'SX'}),
139139
(2,3,{'phase':np.broadcast_to(['a','b','c'],(2,3)),
140-
'O':Rotation.from_random((2,3)),
140+
'O':(2,3),
141141
'V_e':np.broadcast_to(np.eye(3),(2,3,3,3)),
142142
'homogenization':['SX','PX']}),
143143
])
144144
def test_material_add(self,kw,N,n):
145+
kw['O'] = Rotation.from_random(kw['O'])
145146
m = ConfigMaterial().material_add(**kw)
146147
assert len(m['material']) == N
147148
assert len(m['material'][0]['constituents']) == n
148149

149150
@pytest.mark.parametrize('shape',[(),(4,),(5,2)])
150-
@pytest.mark.parametrize('kw',[{'V_e':np.random.rand(3,3)},
151-
{'O':np.random.rand(4)},
152-
{'v':np.array(2)}])
153-
def test_material_add_invalid(self,kw,shape):
151+
@pytest.mark.parametrize('kw',[{'V_e':(3,3)},
152+
{'O':4},
153+
{'v':np.array([2])}])
154+
def test_material_add_invalid(self,np_rng,kw,shape):
155+
kw = {arg:(np_rng.random(val) if not type(val) is np.ndarray else val) for arg,val in kw.items()}
154156
kw = {arg:np.broadcast_to(val,shape+val.shape) for arg,val in kw.items()}
155157
with pytest.raises(ValueError):
156158
ConfigMaterial().material_add(**kw)

python/tests/test_Crystal.py

+7-7
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ def test_invalid_init(self,lattice,family):
1313
with pytest.raises(KeyError):
1414
Crystal(family=family,lattice=lattice)
1515

16-
def test_eq(self):
17-
family = np.random.choice(list(damask._crystal.lattice_symmetries.values()))
16+
def test_eq(self,np_rng):
17+
family = np_rng.choice(list(damask._crystal.lattice_symmetries.values()))
1818
assert Crystal(family=family) == Crystal(family=family)
1919

2020
def test_double_to_lattice(self):
@@ -46,9 +46,9 @@ def test_basis_invalid(self):
4646
with pytest.raises(KeyError):
4747
Crystal(family='cubic').basis_real
4848

49-
def test_basis_real(self):
50-
for gamma in np.random.random(2**8)*np.pi:
51-
basis = np.tril(np.random.random((3,3))+1e-6)
49+
def test_basis_real(self,np_rng):
50+
for gamma in np_rng.random(2**8)*np.pi:
51+
basis = np.tril(np_rng.random((3,3))+1e-6)
5252
basis[1,:2] = basis[1,1]*np.array([np.cos(gamma),np.sin(gamma)])
5353
basis[2,:2] = basis[2,:2]*2-1
5454
lengths = np.linalg.norm(basis,axis=-1)
@@ -139,8 +139,8 @@ def test_related(self,crystal):
139139
@pytest.mark.parametrize('crystal', [Crystal(lattice='cF'),
140140
Crystal(lattice='cI'),
141141
Crystal(lattice='hP')])
142-
def test_related_invalid_target(self,crystal):
143-
relationship = np.random.choice(crystal.orientation_relationships)
142+
def test_related_invalid_target(self,np_rng,crystal):
143+
relationship = np_rng.choice(crystal.orientation_relationships)
144144
with pytest.raises(ValueError):
145145
crystal.relation_operations(relationship,crystal)
146146

0 commit comments

Comments
 (0)