reference Data for ODF sampling (hybridIA) + skeleton of a test
This commit is contained in:
parent
95b85626d8
commit
d2cfcdaca0
|
@ -1,6 +1,8 @@
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
from . import mechanics
|
from . import mechanics
|
||||||
|
from . import util
|
||||||
|
from . import grid_filters
|
||||||
|
|
||||||
_P = -1
|
_P = -1
|
||||||
|
|
||||||
|
@ -647,13 +649,56 @@ class Rotation:
|
||||||
|
|
||||||
return Rotation(q.reshape(r.shape[:-1]+(4,)) if shape is not None else q)._standardize()
|
return Rotation(q.reshape(r.shape[:-1]+(4,)) if shape is not None else q)._standardize()
|
||||||
|
|
||||||
# for compatibility (old names do not follow convention)
|
# for compatibility
|
||||||
fromEulers = from_Eulers
|
|
||||||
fromQuaternion = from_quaternion
|
|
||||||
asAxisAngle = as_axis_angle
|
|
||||||
__mul__ = __matmul__
|
__mul__ = __matmul__
|
||||||
|
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def from_ODF(weights,Eulers,N=500,degrees=True,fractions=True,seed=None):
|
||||||
|
"""
|
||||||
|
Sample discrete orientations from a binned ODF.
|
||||||
|
|
||||||
|
References
|
||||||
|
----------
|
||||||
|
P. Eisenlohr, F. Roters, Computational Materials Science 42(4), 670-678, 2008
|
||||||
|
https://doi.org/10.1016/j.commatsci.2007.09.015
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
fname : file, str, or pathlib.Path
|
||||||
|
ODF file containing normalized probability (labeled 'intensity')
|
||||||
|
on a grid in Euler space (labeled 'euler').
|
||||||
|
N : integer, optional
|
||||||
|
Number of discrete orientations to be sampled from the given ODF.
|
||||||
|
Defaults to 500.
|
||||||
|
degrees : boolean, optional
|
||||||
|
Euler grid values are in degrees. Defaults to True.
|
||||||
|
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
|
||||||
|
A seed to initialize the BitGenerator. Defaults to None, i.e. unpredictable entropy
|
||||||
|
will be pulled from the OS.
|
||||||
|
|
||||||
|
Notes
|
||||||
|
-----
|
||||||
|
Explain here the different things that need to be considered
|
||||||
|
|
||||||
|
"""
|
||||||
|
def _dg(eu,deg):
|
||||||
|
"""Return infinitesimal Euler space volume of bin(s)."""
|
||||||
|
Eulers_sorted = eu[np.lexsort((eu[:,0],eu[:,1],eu[:,2]))]
|
||||||
|
steps,size,_ = grid_filters.cell_coord0_gridSizeOrigin(Eulers_sorted)
|
||||||
|
delta = np.radians(size/steps) if deg else size/steps
|
||||||
|
return delta[0]*2.0*np.sin(delta[1]/2.0)*delta[2] / 8.0 / np.pi**2 * np.sin(np.radians(eu[:,1]) if deg else eu[:,1])
|
||||||
|
|
||||||
|
dg = 1.0 if fractions else _dg(Eulers,degrees)
|
||||||
|
dV_V = dg * np.maximum(0.0,weights.squeeze())
|
||||||
|
orientations = Rotation.from_Eulers(Eulers[util.hybrid_IA(dV_V,N,seed)],degrees)
|
||||||
|
|
||||||
|
return orientations
|
||||||
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def from_spherical_component(center,sigma,N=500,degrees=True,seed=None):
|
def from_spherical_component(center,sigma,N=500,degrees=True,seed=None):
|
||||||
"""
|
"""
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -1,11 +1,11 @@
|
||||||
import os
|
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
import numpy as np
|
import numpy as np
|
||||||
from scipy import stats
|
from scipy import stats
|
||||||
|
|
||||||
from damask import Rotation
|
from damask import Rotation
|
||||||
|
from damask import Table
|
||||||
from damask import _rotation
|
from damask import _rotation
|
||||||
|
from damask import grid_filters
|
||||||
|
|
||||||
n = 1000
|
n = 1000
|
||||||
atol=1.e-4
|
atol=1.e-4
|
||||||
|
@ -13,7 +13,7 @@ atol=1.e-4
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def reference_dir(reference_dir_base):
|
def reference_dir(reference_dir_base):
|
||||||
"""Directory containing reference results."""
|
"""Directory containing reference results."""
|
||||||
return os.path.join(reference_dir_base,'Rotation')
|
return reference_dir_base/'Rotation'
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def set_of_rotations(set_of_quaternions):
|
def set_of_rotations(set_of_quaternions):
|
||||||
|
@ -943,3 +943,39 @@ class TestRotation:
|
||||||
sigma_out = np.degrees(np.std(dist))
|
sigma_out = np.degrees(np.std(dist))
|
||||||
p = np.average(p)
|
p = np.average(p)
|
||||||
assert (.9 < sigma/sigma_out < 1.1) and p > 1e-2, f'{sigma/sigma_out},{p}'
|
assert (.9 < sigma/sigma_out < 1.1) and p > 1e-2, f'{sigma/sigma_out},{p}'
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('fractions',[True,False])
|
||||||
|
@pytest.mark.parametrize('degrees',[True,False])
|
||||||
|
@pytest.mark.parametrize('N',[2**13,2**14,2**15])
|
||||||
|
def test_ODF_cell(self,reference_dir,fractions,degrees,N):
|
||||||
|
steps = np.array([144,36,36])
|
||||||
|
limits = np.array([360.,90.,90.])
|
||||||
|
rng = tuple(zip(np.zeros(3),limits))
|
||||||
|
|
||||||
|
weights = Table.load(reference_dir/'ODF_experimental_cell.txt').get('intensity').flatten()
|
||||||
|
Eulers = grid_filters.cell_coord0(steps,limits)
|
||||||
|
Eulers = np.radians(Eulers) if not degrees else Eulers
|
||||||
|
|
||||||
|
Eulers_r = Rotation.from_ODF(weights,Eulers.reshape(-1,3,order='F'),N,degrees,fractions).as_Eulers(True)
|
||||||
|
weights_r = np.histogramdd(Eulers_r,steps,rng)[0].flatten(order='F')/N * np.sum(weights)
|
||||||
|
|
||||||
|
if fractions: assert np.sqrt(((weights_r - weights) ** 2).mean()) < 4
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('degrees',[True,False])
|
||||||
|
@pytest.mark.parametrize('N',[2**13,2**14,2**15])
|
||||||
|
def test_ODF_node(self,reference_dir,degrees,N):
|
||||||
|
steps = np.array([144,36,36])
|
||||||
|
limits = np.array([360.,90.,90.])
|
||||||
|
rng = tuple(zip(np.zeros(3)-limits/steps*.5,limits-limits/steps*.5))
|
||||||
|
|
||||||
|
weights = Table.load(reference_dir/'ODF_experimental.txt').get('intensity')
|
||||||
|
weights = weights.reshape(steps+1,order='F')[:-1,:-1,:-1].reshape(-1,order='F')
|
||||||
|
|
||||||
|
Eulers = grid_filters.node_coord0(steps,limits)[:-1,:-1,:-1]
|
||||||
|
Eulers = np.radians(Eulers) if not degrees else Eulers
|
||||||
|
|
||||||
|
Eulers_r = Rotation.from_ODF(weights,Eulers.reshape(-1,3,order='F'),N,degrees).as_Eulers(True)
|
||||||
|
weights_r = np.histogramdd(Eulers_r,steps,rng)[0].flatten(order='F')/N * np.sum(weights)
|
||||||
|
|
||||||
|
assert np.sqrt(((weights_r - weights) ** 2).mean()) < 5
|
||||||
|
|
Loading…
Reference in New Issue