Merge remote-tracking branch 'origin/development' into modularize-mech
This commit is contained in:
commit
8429a9d695
2
PRIVATE
2
PRIVATE
|
@ -1 +1 @@
|
||||||
Subproject commit 624218a2b8224b57c3e5d2338517d3a41a3c4f0b
|
Subproject commit 281e7eb84f76a2974a50eb54faf35ea25ec89b20
|
|
@ -15,12 +15,12 @@ from . import seeds # noqa
|
||||||
from . import mechanics # noqa
|
from . import mechanics # noqa
|
||||||
from . import solver # noqa
|
from . import solver # noqa
|
||||||
from . import grid_filters # noqa
|
from . import grid_filters # noqa
|
||||||
from ._lattice import Symmetry, Lattice# noqa
|
from . import lattice # noqa
|
||||||
from ._table import Table # noqa
|
|
||||||
from ._rotation import Rotation # noqa
|
from ._rotation import Rotation # noqa
|
||||||
|
from ._orientation import Orientation # noqa
|
||||||
|
from ._table import Table # noqa
|
||||||
from ._vtk import VTK # noqa
|
from ._vtk import VTK # noqa
|
||||||
from ._colormap import Colormap # noqa
|
from ._colormap import Colormap # noqa
|
||||||
from ._orientation import Orientation # noqa
|
|
||||||
from ._config import Config # noqa
|
from ._config import Config # noqa
|
||||||
from ._configmaterial import ConfigMaterial # noqa
|
from ._configmaterial import ConfigMaterial # noqa
|
||||||
from ._geom import Geom # noqa
|
from ._geom import Geom # noqa
|
||||||
|
|
|
@ -3,8 +3,8 @@ import copy
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
from . import Config
|
from . import Config
|
||||||
from . import Lattice
|
|
||||||
from . import Rotation
|
from . import Rotation
|
||||||
|
from . import Orientation
|
||||||
|
|
||||||
class ConfigMaterial(Config):
|
class ConfigMaterial(Config):
|
||||||
"""Material configuration."""
|
"""Material configuration."""
|
||||||
|
@ -152,7 +152,7 @@ class ConfigMaterial(Config):
|
||||||
for k,v in self['phase'].items():
|
for k,v in self['phase'].items():
|
||||||
if 'lattice' in v:
|
if 'lattice' in v:
|
||||||
try:
|
try:
|
||||||
Lattice(v['lattice'])
|
Orientation(lattice=v['lattice'])
|
||||||
except KeyError:
|
except KeyError:
|
||||||
s = v['lattice']
|
s = v['lattice']
|
||||||
print(f"Invalid lattice: '{s}' in phase '{k}'")
|
print(f"Invalid lattice: '{s}' in phase '{k}'")
|
||||||
|
|
|
@ -20,7 +20,7 @@ class Geom:
|
||||||
|
|
||||||
def __init__(self,material,size,origin=[0.0,0.0,0.0],comments=[]):
|
def __init__(self,material,size,origin=[0.0,0.0,0.0],comments=[]):
|
||||||
"""
|
"""
|
||||||
New geometry definition from array of material, size, and origin.
|
New geometry definition from array of materials, size, and origin.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
|
@ -34,28 +34,10 @@ class Geom:
|
||||||
Comment lines.
|
Comment lines.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if len(material.shape) != 3:
|
self.material = material
|
||||||
raise ValueError(f'Invalid material shape {material.shape}.')
|
self.size = size
|
||||||
elif material.dtype not in np.sctypes['float'] + np.sctypes['int']:
|
self.origin = origin
|
||||||
raise TypeError(f'Invalid material data type {material.dtype}.')
|
self.comments = comments
|
||||||
else:
|
|
||||||
self.material = np.copy(material)
|
|
||||||
|
|
||||||
if self.material.dtype in np.sctypes['float'] and \
|
|
||||||
np.all(self.material == self.material.astype(int).astype(float)):
|
|
||||||
self.material = self.material.astype(int)
|
|
||||||
|
|
||||||
if len(size) != 3 or any(np.array(size) <= 0):
|
|
||||||
raise ValueError(f'Invalid size {size}.')
|
|
||||||
else:
|
|
||||||
self.size = np.array(size)
|
|
||||||
|
|
||||||
if len(origin) != 3:
|
|
||||||
raise ValueError(f'Invalid origin {origin}.')
|
|
||||||
else:
|
|
||||||
self.origin = np.array(origin)
|
|
||||||
|
|
||||||
self.comments = [str(c) for c in comments] if isinstance(comments,list) else [str(comments)]
|
|
||||||
|
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
|
@ -113,13 +95,68 @@ class Geom:
|
||||||
return util.return_message(message)
|
return util.return_message(message)
|
||||||
|
|
||||||
|
|
||||||
|
@property
|
||||||
|
def material(self):
|
||||||
|
"""Material indices."""
|
||||||
|
return self._material
|
||||||
|
|
||||||
|
@material.setter
|
||||||
|
def material(self,material):
|
||||||
|
if len(material.shape) != 3:
|
||||||
|
raise ValueError(f'Invalid material shape {material.shape}.')
|
||||||
|
elif material.dtype not in np.sctypes['float'] + np.sctypes['int']:
|
||||||
|
raise TypeError(f'Invalid material data type {material.dtype}.')
|
||||||
|
else:
|
||||||
|
self._material = np.copy(material)
|
||||||
|
|
||||||
|
if self.material.dtype in np.sctypes['float'] and \
|
||||||
|
np.all(self.material == self.material.astype(int).astype(float)):
|
||||||
|
self._material = self.material.astype(int)
|
||||||
|
|
||||||
|
|
||||||
|
@property
|
||||||
|
def size(self):
|
||||||
|
"""Physical size of geometry in meter."""
|
||||||
|
return self._size
|
||||||
|
|
||||||
|
@size.setter
|
||||||
|
def size(self,size):
|
||||||
|
if len(size) != 3 or any(np.array(size) <= 0):
|
||||||
|
raise ValueError(f'Invalid size {size}.')
|
||||||
|
else:
|
||||||
|
self._size = np.array(size)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def origin(self):
|
||||||
|
"""Coordinates of geometry origin in meter."""
|
||||||
|
return self._origin
|
||||||
|
|
||||||
|
@origin.setter
|
||||||
|
def origin(self,origin):
|
||||||
|
if len(origin) != 3:
|
||||||
|
raise ValueError(f'Invalid origin {origin}.')
|
||||||
|
else:
|
||||||
|
self._origin = np.array(origin)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def comments(self):
|
||||||
|
"""Comments/history of geometry."""
|
||||||
|
return self._comments
|
||||||
|
|
||||||
|
@comments.setter
|
||||||
|
def comments(self,comments):
|
||||||
|
self._comments = [str(c) for c in comments] if isinstance(comments,list) else [str(comments)]
|
||||||
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def grid(self):
|
def grid(self):
|
||||||
|
"""Grid dimension of geometry."""
|
||||||
return np.asarray(self.material.shape)
|
return np.asarray(self.material.shape)
|
||||||
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def N_materials(self):
|
def N_materials(self):
|
||||||
|
"""Number of (unique) material indices within geometry."""
|
||||||
return np.unique(self.material).size
|
return np.unique(self.material).size
|
||||||
|
|
||||||
|
|
||||||
|
@ -132,7 +169,7 @@ class Geom:
|
||||||
----------
|
----------
|
||||||
fname : str or or pathlib.Path
|
fname : str or or pathlib.Path
|
||||||
Geometry file to read.
|
Geometry file to read.
|
||||||
Valid extension is .vtr, it will be appended if not given.
|
Valid extension is .vtr, which will be appended if not given.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
v = VTK.load(fname if str(fname).endswith('.vtr') else str(fname)+'.vtr')
|
v = VTK.load(fname if str(fname).endswith('.vtr') else str(fname)+'.vtr')
|
||||||
|
@ -153,7 +190,7 @@ class Geom:
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
fname : str or file handle
|
fname : str, pathlib.Path, or file handle
|
||||||
Geometry file to read.
|
Geometry file to read.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
@ -221,26 +258,26 @@ class Geom:
|
||||||
fname : str
|
fname : str
|
||||||
Filename of the DREAM.3D file
|
Filename of the DREAM.3D file
|
||||||
base_group : str
|
base_group : str
|
||||||
Name of the group (folder) below 'DataContainers'. For example
|
Name of the group (folder) below 'DataContainers',
|
||||||
'SyntheticVolumeDataContainer'.
|
for example 'SyntheticVolumeDataContainer'.
|
||||||
point_data : str, optional
|
point_data : str, optional
|
||||||
Name of the group (folder) containing the pointwise material data,
|
Name of the group (folder) containing the pointwise material data,
|
||||||
for example 'CellData'. Defaults to None, in which case points consecutively numbered.
|
for example 'CellData'. Defaults to None, in which case points are consecutively numbered.
|
||||||
material : str, optional
|
material : str, optional
|
||||||
Name of the dataset containing the material ID. Defaults to
|
Name of the dataset containing the material ID.
|
||||||
'FeatureIds'.
|
Defaults to 'FeatureIds'.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
root_dir ='DataContainers'
|
root_dir ='DataContainers'
|
||||||
f = h5py.File(fname, 'r')
|
f = h5py.File(fname, 'r')
|
||||||
g = path.join(root_dir,base_group,'_SIMPL_GEOMETRY')
|
g = path.join(root_dir,base_group,'_SIMPL_GEOMETRY')
|
||||||
size = f[path.join(g,'DIMENSIONS')][()] * f[path.join(g,'SPACING')][()]
|
|
||||||
grid = f[path.join(g,'DIMENSIONS')][()]
|
grid = f[path.join(g,'DIMENSIONS')][()]
|
||||||
|
size = f[path.join(g,'SPACING')][()] * grid
|
||||||
origin = f[path.join(g,'ORIGIN')][()]
|
origin = f[path.join(g,'ORIGIN')][()]
|
||||||
group_pointwise = path.join(root_dir,base_group,point_data)
|
|
||||||
|
|
||||||
ma = np.arange(1,np.product(grid)+1,dtype=int) if point_data is None else \
|
ma = np.arange(grid.prod(),dtype=int) \
|
||||||
np.reshape(f[path.join(group_pointwise,material)],grid.prod())
|
if point_data is None else \
|
||||||
|
np.reshape(f[path.join(root_dir,base_group,point_data,material)],grid.prod())
|
||||||
|
|
||||||
return Geom(ma.reshape(grid,order='F'),size,origin,util.execution_stamp('Geom','load_DREAM3D'))
|
return Geom(ma.reshape(grid,order='F'),size,origin,util.execution_stamp('Geom','load_DREAM3D'))
|
||||||
|
|
||||||
|
@ -248,18 +285,18 @@ class Geom:
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def from_table(table,coordinates,labels):
|
def from_table(table,coordinates,labels):
|
||||||
"""
|
"""
|
||||||
Load an ASCII table.
|
Derive geometry from an ASCII table.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
table : damask.Table
|
table : damask.Table
|
||||||
Table that contains material information.
|
Table that contains material information.
|
||||||
coordinates : str
|
coordinates : str
|
||||||
Label of the column containing the vector of spatial coordinates.
|
Label of the vector column containing the spatial coordinates.
|
||||||
Need to be ordered (1./x fast, 3./z slow).
|
Need to be ordered (1./x fast, 3./z slow).
|
||||||
labels : str or list of str
|
labels : str or list of str
|
||||||
Label(s) of the columns containing the material definition.
|
Label(s) of the columns containing the material definition.
|
||||||
Each unique combintation of values results in a material.
|
Each unique combintation of values results in one material ID.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
grid,size,origin = grid_filters.cell_coord0_gridSizeOrigin(table.get(coordinates))
|
grid,size,origin = grid_filters.cell_coord0_gridSizeOrigin(table.get(coordinates))
|
||||||
|
@ -293,8 +330,8 @@ class Geom:
|
||||||
weights : numpy.ndarray of shape (seeds.shape[0])
|
weights : numpy.ndarray of shape (seeds.shape[0])
|
||||||
Weights of the seeds. Setting all weights to 1.0 gives a standard Voronoi tessellation.
|
Weights of the seeds. Setting all weights to 1.0 gives a standard Voronoi tessellation.
|
||||||
material : numpy.ndarray of shape (seeds.shape[0]), optional
|
material : numpy.ndarray of shape (seeds.shape[0]), optional
|
||||||
Material ID of the seeds. Defaults to None, in which case materials are
|
Material ID of the seeds.
|
||||||
consecutively numbered.
|
Defaults to None, in which case materials are consecutively numbered.
|
||||||
periodic : Boolean, optional
|
periodic : Boolean, optional
|
||||||
Perform a periodic tessellation. Defaults to True.
|
Perform a periodic tessellation. Defaults to True.
|
||||||
|
|
||||||
|
@ -342,8 +379,8 @@ class Geom:
|
||||||
seeds : numpy.ndarray of shape (:,3)
|
seeds : numpy.ndarray of shape (:,3)
|
||||||
Position of the seed points in meter. All points need to lay within the box.
|
Position of the seed points in meter. All points need to lay within the box.
|
||||||
material : numpy.ndarray of shape (seeds.shape[0]), optional
|
material : numpy.ndarray of shape (seeds.shape[0]), optional
|
||||||
Material ID of the seeds. Defaults to None, in which case materials are
|
Material ID of the seeds.
|
||||||
consecutively numbered.
|
Defaults to None, in which case materials are consecutively numbered.
|
||||||
periodic : Boolean, optional
|
periodic : Boolean, optional
|
||||||
Perform a periodic tessellation. Defaults to True.
|
Perform a periodic tessellation. Defaults to True.
|
||||||
|
|
||||||
|
@ -438,19 +475,19 @@ class Geom:
|
||||||
|
|
||||||
References
|
References
|
||||||
----------
|
----------
|
||||||
Surface curvature in triply-periodic minimal surface architectures as
|
|
||||||
a distinct design parameter in preparing advanced tissue engineering scaffolds
|
|
||||||
Sébastien B G Blanquer, Maike Werner, Markus Hannula, Shahriar Sharifi,
|
Sébastien B G Blanquer, Maike Werner, Markus Hannula, Shahriar Sharifi,
|
||||||
Guillaume P R Lajoinie, David Eglin, Jari Hyttinen, André A Poot, and Dirk W Grijpma
|
Guillaume P R Lajoinie, David Eglin, Jari Hyttinen, André A Poot, and Dirk W Grijpma
|
||||||
10.1088/1758-5090/aa6553
|
Surface curvature in triply-periodic minimal surface architectures as
|
||||||
|
a distinct design parameter in preparing advanced tissue engineering scaffolds
|
||||||
|
https://doi.org/10.1088/1758-5090/aa6553
|
||||||
|
|
||||||
Triply Periodic Bicontinuous Cubic Microdomain Morphologies by Symmetries
|
|
||||||
Meinhard Wohlgemuth, Nataliya Yufa, James Hoffman, and Edwin L. Thomas
|
Meinhard Wohlgemuth, Nataliya Yufa, James Hoffman, and Edwin L. Thomas
|
||||||
10.1021/ma0019499
|
Triply Periodic Bicontinuous Cubic Microdomain Morphologies by Symmetries
|
||||||
|
https://doi.org/10.1021/ma0019499
|
||||||
|
|
||||||
Minisurf – A minimal surface generator for finite element modeling and additive manufacturing
|
|
||||||
Meng-Ting Hsieh, Lorenzo Valdevit
|
Meng-Ting Hsieh, Lorenzo Valdevit
|
||||||
10.1016/j.simpa.2020.100026
|
Minisurf – A minimal surface generator for finite element modeling and additive manufacturing
|
||||||
|
https://doi.org/10.1016/j.simpa.2020.100026
|
||||||
|
|
||||||
"""
|
"""
|
||||||
x,y,z = np.meshgrid(periods*2.0*np.pi*(np.arange(grid[0])+0.5)/grid[0],
|
x,y,z = np.meshgrid(periods*2.0*np.pi*(np.arange(grid[0])+0.5)/grid[0],
|
||||||
|
@ -465,7 +502,7 @@ class Geom:
|
||||||
|
|
||||||
def save(self,fname,compress=True):
|
def save(self,fname,compress=True):
|
||||||
"""
|
"""
|
||||||
Store as vtk rectilinear grid.
|
Store as VTK rectilinear grid.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
|
@ -689,7 +726,7 @@ class Geom:
|
||||||
|
|
||||||
|
|
||||||
def renumber(self):
|
def renumber(self):
|
||||||
"""Renumber sorted material indices to 0,...,N-1."""
|
"""Renumber sorted material indices as 0,...,N-1."""
|
||||||
_,renumbered = np.unique(self.material,return_inverse=True)
|
_,renumbered = np.unique(self.material,return_inverse=True)
|
||||||
|
|
||||||
return Geom(material = renumbered.reshape(self.grid),
|
return Geom(material = renumbered.reshape(self.grid),
|
||||||
|
|
|
@ -1,646 +0,0 @@
|
||||||
import numpy as np
|
|
||||||
|
|
||||||
|
|
||||||
class Symmetry:
|
|
||||||
"""
|
|
||||||
Symmetry-related operations for crystal systems.
|
|
||||||
|
|
||||||
References
|
|
||||||
----------
|
|
||||||
https://en.wikipedia.org/wiki/Crystal_system
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
crystal_systems = [None,'orthorhombic','tetragonal','hexagonal','cubic']
|
|
||||||
|
|
||||||
def __init__(self, system = None):
|
|
||||||
"""
|
|
||||||
Symmetry Definition.
|
|
||||||
|
|
||||||
Parameters
|
|
||||||
----------
|
|
||||||
system : {None,'orthorhombic','tetragonal','hexagonal','cubic'}, optional
|
|
||||||
Name of the crystal system. Defaults to 'None'.
|
|
||||||
|
|
||||||
"""
|
|
||||||
if system is not None and system.lower() not in self.crystal_systems:
|
|
||||||
raise KeyError(f'Crystal system "{system}" is unknown')
|
|
||||||
|
|
||||||
self.system = system.lower() if isinstance(system,str) else system
|
|
||||||
|
|
||||||
|
|
||||||
def __copy__(self):
|
|
||||||
"""Copy."""
|
|
||||||
return self.__class__(self.system)
|
|
||||||
|
|
||||||
copy = __copy__
|
|
||||||
|
|
||||||
|
|
||||||
def __repr__(self):
|
|
||||||
"""Readable string."""
|
|
||||||
return f'{self.system}'
|
|
||||||
|
|
||||||
|
|
||||||
def __eq__(self, other):
|
|
||||||
"""
|
|
||||||
Equal to other.
|
|
||||||
|
|
||||||
Parameters
|
|
||||||
----------
|
|
||||||
other : Symmetry
|
|
||||||
Symmetry to check for equality.
|
|
||||||
|
|
||||||
"""
|
|
||||||
return self.system == other.system
|
|
||||||
|
|
||||||
def __neq__(self, other):
|
|
||||||
"""
|
|
||||||
Not Equal to other.
|
|
||||||
|
|
||||||
Parameters
|
|
||||||
----------
|
|
||||||
other : Symmetry
|
|
||||||
Symmetry to check for inequality.
|
|
||||||
|
|
||||||
"""
|
|
||||||
return not self.__eq__(other)
|
|
||||||
|
|
||||||
def __cmp__(self,other):
|
|
||||||
"""
|
|
||||||
Linear ordering.
|
|
||||||
|
|
||||||
Parameters
|
|
||||||
----------
|
|
||||||
other : Symmetry
|
|
||||||
Symmetry to check for for order.
|
|
||||||
|
|
||||||
"""
|
|
||||||
myOrder = self.crystal_systems.index(self.system)
|
|
||||||
otherOrder = self.crystal_systems.index(other.system)
|
|
||||||
return (myOrder > otherOrder) - (myOrder < otherOrder)
|
|
||||||
|
|
||||||
|
|
||||||
@property
|
|
||||||
def symmetry_operations(self):
|
|
||||||
"""Symmetry operations as quaternions."""
|
|
||||||
if self.system == 'cubic':
|
|
||||||
sym_quats = [
|
|
||||||
[ 1.0, 0.0, 0.0, 0.0 ],
|
|
||||||
[ 0.0, 1.0, 0.0, 0.0 ],
|
|
||||||
[ 0.0, 0.0, 1.0, 0.0 ],
|
|
||||||
[ 0.0, 0.0, 0.0, 1.0 ],
|
|
||||||
[ 0.0, 0.0, 0.5*np.sqrt(2), 0.5*np.sqrt(2) ],
|
|
||||||
[ 0.0, 0.0, 0.5*np.sqrt(2),-0.5*np.sqrt(2) ],
|
|
||||||
[ 0.0, 0.5*np.sqrt(2), 0.0, 0.5*np.sqrt(2) ],
|
|
||||||
[ 0.0, 0.5*np.sqrt(2), 0.0, -0.5*np.sqrt(2) ],
|
|
||||||
[ 0.0, 0.5*np.sqrt(2),-0.5*np.sqrt(2), 0.0 ],
|
|
||||||
[ 0.0, -0.5*np.sqrt(2),-0.5*np.sqrt(2), 0.0 ],
|
|
||||||
[ 0.5, 0.5, 0.5, 0.5 ],
|
|
||||||
[-0.5, 0.5, 0.5, 0.5 ],
|
|
||||||
[-0.5, 0.5, 0.5, -0.5 ],
|
|
||||||
[-0.5, 0.5, -0.5, 0.5 ],
|
|
||||||
[-0.5, -0.5, 0.5, 0.5 ],
|
|
||||||
[-0.5, -0.5, 0.5, -0.5 ],
|
|
||||||
[-0.5, -0.5, -0.5, 0.5 ],
|
|
||||||
[-0.5, 0.5, -0.5, -0.5 ],
|
|
||||||
[-0.5*np.sqrt(2), 0.0, 0.0, 0.5*np.sqrt(2) ],
|
|
||||||
[ 0.5*np.sqrt(2), 0.0, 0.0, 0.5*np.sqrt(2) ],
|
|
||||||
[-0.5*np.sqrt(2), 0.0, 0.5*np.sqrt(2), 0.0 ],
|
|
||||||
[-0.5*np.sqrt(2), 0.0, -0.5*np.sqrt(2), 0.0 ],
|
|
||||||
[-0.5*np.sqrt(2), 0.5*np.sqrt(2), 0.0, 0.0 ],
|
|
||||||
[-0.5*np.sqrt(2),-0.5*np.sqrt(2), 0.0, 0.0 ],
|
|
||||||
]
|
|
||||||
elif self.system == 'hexagonal':
|
|
||||||
sym_quats = [
|
|
||||||
[ 1.0, 0.0, 0.0, 0.0 ],
|
|
||||||
[-0.5*np.sqrt(3), 0.0, 0.0, -0.5 ],
|
|
||||||
[ 0.5, 0.0, 0.0, 0.5*np.sqrt(3) ],
|
|
||||||
[ 0.0, 0.0, 0.0, 1.0 ],
|
|
||||||
[-0.5, 0.0, 0.0, 0.5*np.sqrt(3) ],
|
|
||||||
[-0.5*np.sqrt(3), 0.0, 0.0, 0.5 ],
|
|
||||||
[ 0.0, 1.0, 0.0, 0.0 ],
|
|
||||||
[ 0.0, -0.5*np.sqrt(3), 0.5, 0.0 ],
|
|
||||||
[ 0.0, 0.5, -0.5*np.sqrt(3), 0.0 ],
|
|
||||||
[ 0.0, 0.0, 1.0, 0.0 ],
|
|
||||||
[ 0.0, -0.5, -0.5*np.sqrt(3), 0.0 ],
|
|
||||||
[ 0.0, 0.5*np.sqrt(3), 0.5, 0.0 ],
|
|
||||||
]
|
|
||||||
elif self.system == 'tetragonal':
|
|
||||||
sym_quats = [
|
|
||||||
[ 1.0, 0.0, 0.0, 0.0 ],
|
|
||||||
[ 0.0, 1.0, 0.0, 0.0 ],
|
|
||||||
[ 0.0, 0.0, 1.0, 0.0 ],
|
|
||||||
[ 0.0, 0.0, 0.0, 1.0 ],
|
|
||||||
[ 0.0, 0.5*np.sqrt(2), 0.5*np.sqrt(2), 0.0 ],
|
|
||||||
[ 0.0, -0.5*np.sqrt(2), 0.5*np.sqrt(2), 0.0 ],
|
|
||||||
[ 0.5*np.sqrt(2), 0.0, 0.0, 0.5*np.sqrt(2) ],
|
|
||||||
[-0.5*np.sqrt(2), 0.0, 0.0, 0.5*np.sqrt(2) ],
|
|
||||||
]
|
|
||||||
elif self.system == 'orthorhombic':
|
|
||||||
sym_quats = [
|
|
||||||
[ 1.0,0.0,0.0,0.0 ],
|
|
||||||
[ 0.0,1.0,0.0,0.0 ],
|
|
||||||
[ 0.0,0.0,1.0,0.0 ],
|
|
||||||
[ 0.0,0.0,0.0,1.0 ],
|
|
||||||
]
|
|
||||||
else:
|
|
||||||
sym_quats = [
|
|
||||||
[ 1.0,0.0,0.0,0.0 ],
|
|
||||||
]
|
|
||||||
return np.array(sym_quats)
|
|
||||||
|
|
||||||
|
|
||||||
def in_FZ(self,rho):
|
|
||||||
"""
|
|
||||||
Check whether given Rodrigues-Frank vector falls into fundamental zone.
|
|
||||||
|
|
||||||
Fundamental zone in Rodrigues space is point symmetric around origin.
|
|
||||||
"""
|
|
||||||
if(rho.shape[-1] != 3):
|
|
||||||
raise ValueError('Input is not a Rodrigues-Frank vector field.')
|
|
||||||
|
|
||||||
rho_abs = np.abs(rho)
|
|
||||||
|
|
||||||
with np.errstate(invalid='ignore'):
|
|
||||||
# using '*'/prod for 'and'
|
|
||||||
if self.system == 'cubic':
|
|
||||||
return np.where(np.prod(np.sqrt(2)-1. >= rho_abs,axis=-1) *
|
|
||||||
(1. >= np.sum(rho_abs,axis=-1)),True,False)
|
|
||||||
elif self.system == 'hexagonal':
|
|
||||||
return np.where(np.prod(1. >= rho_abs,axis=-1) *
|
|
||||||
(2. >= np.sqrt(3)*rho_abs[...,0] + rho_abs[...,1]) *
|
|
||||||
(2. >= np.sqrt(3)*rho_abs[...,1] + rho_abs[...,0]) *
|
|
||||||
(2. >= np.sqrt(3) + rho_abs[...,2]),True,False)
|
|
||||||
elif self.system == 'tetragonal':
|
|
||||||
return np.where(np.prod(1. >= rho_abs[...,:2],axis=-1) *
|
|
||||||
(np.sqrt(2) >= rho_abs[...,0] + rho_abs[...,1]) *
|
|
||||||
(np.sqrt(2) >= rho_abs[...,2] + 1.),True,False)
|
|
||||||
elif self.system == 'orthorhombic':
|
|
||||||
return np.where(np.prod(1. >= rho_abs,axis=-1),True,False)
|
|
||||||
else:
|
|
||||||
return np.where(np.all(np.isfinite(rho_abs),axis=-1),True,False)
|
|
||||||
|
|
||||||
|
|
||||||
def in_disorientation_SST(self,rho):
|
|
||||||
"""
|
|
||||||
Check whether given Rodrigues-Frank vector (of misorientation) falls into standard stereographic triangle.
|
|
||||||
|
|
||||||
References
|
|
||||||
----------
|
|
||||||
A. Heinz and P. Neumann, Acta Crystallographica Section A 47:780-789, 1991
|
|
||||||
https://doi.org/10.1107/S0108767391006864
|
|
||||||
|
|
||||||
"""
|
|
||||||
if(rho.shape[-1] != 3):
|
|
||||||
raise ValueError('Input is not a Rodrigues-Frank vector field.')
|
|
||||||
|
|
||||||
with np.errstate(invalid='ignore'):
|
|
||||||
# using '*' for 'and'
|
|
||||||
if self.system == 'cubic':
|
|
||||||
return np.where((rho[...,0] >= rho[...,1]) * \
|
|
||||||
(rho[...,1] >= rho[...,2]) * \
|
|
||||||
(rho[...,2] >= 0),True,False)
|
|
||||||
elif self.system == 'hexagonal':
|
|
||||||
return np.where((rho[...,0] >= rho[...,1]*np.sqrt(3)) * \
|
|
||||||
(rho[...,1] >= 0) * \
|
|
||||||
(rho[...,2] >= 0),True,False)
|
|
||||||
elif self.system == 'tetragonal':
|
|
||||||
return np.where((rho[...,0] >= rho[...,1]) * \
|
|
||||||
(rho[...,1] >= 0) * \
|
|
||||||
(rho[...,2] >= 0),True,False)
|
|
||||||
elif self.system == 'orthorhombic':
|
|
||||||
return np.where((rho[...,0] >= 0) * \
|
|
||||||
(rho[...,1] >= 0) * \
|
|
||||||
(rho[...,2] >= 0),True,False)
|
|
||||||
else:
|
|
||||||
return np.ones_like(rho[...,0],dtype=bool)
|
|
||||||
|
|
||||||
|
|
||||||
#ToDo: IPF color in separate function
|
|
||||||
def in_SST(self,vector,proper=False,color=False):
|
|
||||||
"""
|
|
||||||
Check whether given vector falls into standard stereographic triangle of own symmetry.
|
|
||||||
|
|
||||||
proper considers only vectors with z >= 0, hence uses two neighboring SSTs.
|
|
||||||
Return inverse pole figure color if requested.
|
|
||||||
Bases are computed from
|
|
||||||
|
|
||||||
>>> basis = {'cubic' : np.linalg.inv(np.array([[0.,0.,1.], # direction of red
|
|
||||||
... [1.,0.,1.]/np.sqrt(2.), # direction of green
|
|
||||||
... [1.,1.,1.]/np.sqrt(3.)]).T), # direction of blue
|
|
||||||
... 'hexagonal' : np.linalg.inv(np.array([[0.,0.,1.], # direction of red
|
|
||||||
... [1.,0.,0.], # direction of green
|
|
||||||
... [np.sqrt(3.),1.,0.]/np.sqrt(4.)]).T), # direction of blue
|
|
||||||
... 'tetragonal' : np.linalg.inv(np.array([[0.,0.,1.], # direction of red
|
|
||||||
... [1.,0.,0.], # direction of green
|
|
||||||
... [1.,1.,0.]/np.sqrt(2.)]).T), # direction of blue
|
|
||||||
... 'orthorhombic': np.linalg.inv(np.array([[0.,0.,1.], # direction of red
|
|
||||||
... [1.,0.,0.], # direction of green
|
|
||||||
... [0.,1.,0.]]).T), # direction of blue
|
|
||||||
... }
|
|
||||||
|
|
||||||
"""
|
|
||||||
if(vector.shape[-1] != 3):
|
|
||||||
raise ValueError('Input is not a 3D vector field.')
|
|
||||||
|
|
||||||
if self.system == 'cubic':
|
|
||||||
basis = {'improper':np.array([ [-1. , 0. , 1. ],
|
|
||||||
[ np.sqrt(2.) , -np.sqrt(2.) , 0. ],
|
|
||||||
[ 0. , np.sqrt(3.) , 0. ] ]),
|
|
||||||
'proper':np.array([ [ 0. , -1. , 1. ],
|
|
||||||
[-np.sqrt(2.) , np.sqrt(2.) , 0. ],
|
|
||||||
[ np.sqrt(3.) , 0. , 0. ] ]),
|
|
||||||
}
|
|
||||||
elif self.system == 'hexagonal':
|
|
||||||
basis = {'improper':np.array([ [ 0. , 0. , 1. ],
|
|
||||||
[ 1. , -np.sqrt(3.) , 0. ],
|
|
||||||
[ 0. , 2. , 0. ] ]),
|
|
||||||
'proper':np.array([ [ 0. , 0. , 1. ],
|
|
||||||
[-1. , np.sqrt(3.) , 0. ],
|
|
||||||
[ np.sqrt(3.) , -1. , 0. ] ]),
|
|
||||||
}
|
|
||||||
elif self.system == 'tetragonal':
|
|
||||||
basis = {'improper':np.array([ [ 0. , 0. , 1. ],
|
|
||||||
[ 1. , -1. , 0. ],
|
|
||||||
[ 0. , np.sqrt(2.) , 0. ] ]),
|
|
||||||
'proper':np.array([ [ 0. , 0. , 1. ],
|
|
||||||
[-1. , 1. , 0. ],
|
|
||||||
[ np.sqrt(2.) , 0. , 0. ] ]),
|
|
||||||
}
|
|
||||||
elif self.system == 'orthorhombic':
|
|
||||||
basis = {'improper':np.array([ [ 0., 0., 1.],
|
|
||||||
[ 1., 0., 0.],
|
|
||||||
[ 0., 1., 0.] ]),
|
|
||||||
'proper':np.array([ [ 0., 0., 1.],
|
|
||||||
[-1., 0., 0.],
|
|
||||||
[ 0., 1., 0.] ]),
|
|
||||||
}
|
|
||||||
else: # direct exit for unspecified symmetry
|
|
||||||
if color:
|
|
||||||
return (np.ones_like(vector[...,0],bool),np.zeros_like(vector))
|
|
||||||
else:
|
|
||||||
return np.ones_like(vector[...,0],bool)
|
|
||||||
|
|
||||||
|
|
||||||
b_i = np.broadcast_to(basis['improper'],vector.shape+(3,))
|
|
||||||
if proper:
|
|
||||||
b_p = np.broadcast_to(basis['proper'], vector.shape+(3,))
|
|
||||||
improper = np.all(np.around(np.einsum('...ji,...i',b_i,vector),12)>=0.0,axis=-1,keepdims=True)
|
|
||||||
theComponents = np.where(np.broadcast_to(improper,vector.shape),
|
|
||||||
np.around(np.einsum('...ji,...i',b_i,vector),12),
|
|
||||||
np.around(np.einsum('...ji,...i',b_p,vector),12))
|
|
||||||
else:
|
|
||||||
vector_ = np.block([vector[...,0:2],np.abs(vector[...,2:3])]) # z component projects identical
|
|
||||||
theComponents = np.around(np.einsum('...ji,...i',b_i,vector_),12)
|
|
||||||
|
|
||||||
in_SST = np.all(theComponents >= 0.0,axis=-1)
|
|
||||||
|
|
||||||
if color: # have to return color array
|
|
||||||
with np.errstate(invalid='ignore',divide='ignore'):
|
|
||||||
rgb = (theComponents/np.linalg.norm(theComponents,axis=-1,keepdims=True))**0.5 # smoothen color ramps
|
|
||||||
rgb = np.minimum(1.,rgb) # limit to maximum intensity
|
|
||||||
rgb /= np.max(rgb,axis=-1,keepdims=True) # normalize to (HS)V = 1
|
|
||||||
rgb[np.broadcast_to(~in_SST.reshape(vector[...,0].shape+(1,)),vector.shape)] = 0.0
|
|
||||||
return (in_SST,rgb)
|
|
||||||
else:
|
|
||||||
return in_SST
|
|
||||||
|
|
||||||
|
|
||||||
# ******************************************************************************************
|
|
||||||
class Lattice: # ToDo: Make a subclass of Symmetry!
|
|
||||||
"""
|
|
||||||
Bravais lattice.
|
|
||||||
|
|
||||||
This contains only a mapping from Bravais lattice to symmetry
|
|
||||||
and orientation relationships. It could include twin and slip systems.
|
|
||||||
|
|
||||||
References
|
|
||||||
----------
|
|
||||||
https://en.wikipedia.org/wiki/Bravais_lattice
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
lattices = {
|
|
||||||
'iso': {'system':None},
|
|
||||||
'triclinic':{'system':None},
|
|
||||||
'bct': {'system':'tetragonal'},
|
|
||||||
'hex': {'system':'hexagonal'},
|
|
||||||
'fcc': {'system':'cubic','c/a':1.0},
|
|
||||||
'bcc': {'system':'cubic','c/a':1.0},
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def __init__(self,lattice,c_over_a=None):
|
|
||||||
"""
|
|
||||||
New lattice of given type.
|
|
||||||
|
|
||||||
Parameters
|
|
||||||
----------
|
|
||||||
lattice : str
|
|
||||||
Bravais lattice.
|
|
||||||
|
|
||||||
"""
|
|
||||||
self.lattice = lattice
|
|
||||||
self.symmetry = Symmetry(self.lattices[lattice]['system'])
|
|
||||||
|
|
||||||
# transition to subclass
|
|
||||||
self.system = self.symmetry.system
|
|
||||||
self.in_SST = self.symmetry.in_SST
|
|
||||||
self.in_FZ = self.symmetry.in_FZ
|
|
||||||
self.in_disorientation_SST = self.symmetry.in_disorientation_SST
|
|
||||||
|
|
||||||
def __repr__(self):
|
|
||||||
"""Report basic lattice information."""
|
|
||||||
return f'Bravais lattice {self.lattice} ({self.symmetry} crystal system)'
|
|
||||||
|
|
||||||
|
|
||||||
# Kurdjomov--Sachs orientation relationship for fcc <-> bcc transformation
|
|
||||||
# from S. Morito et al., Journal of Alloys and Compounds 577:s587-s592, 2013
|
|
||||||
# also see K. Kitahara et al., Acta Materialia 54:1279-1288, 2006
|
|
||||||
_KS = {'mapping':{'fcc':0,'bcc':1},
|
|
||||||
'planes': np.array([
|
|
||||||
[[ 1, 1, 1],[ 0, 1, 1]],
|
|
||||||
[[ 1, 1, 1],[ 0, 1, 1]],
|
|
||||||
[[ 1, 1, 1],[ 0, 1, 1]],
|
|
||||||
[[ 1, 1, 1],[ 0, 1, 1]],
|
|
||||||
[[ 1, 1, 1],[ 0, 1, 1]],
|
|
||||||
[[ 1, 1, 1],[ 0, 1, 1]],
|
|
||||||
[[ 1, -1, 1],[ 0, 1, 1]],
|
|
||||||
[[ 1, -1, 1],[ 0, 1, 1]],
|
|
||||||
[[ 1, -1, 1],[ 0, 1, 1]],
|
|
||||||
[[ 1, -1, 1],[ 0, 1, 1]],
|
|
||||||
[[ 1, -1, 1],[ 0, 1, 1]],
|
|
||||||
[[ 1, -1, 1],[ 0, 1, 1]],
|
|
||||||
[[ -1, 1, 1],[ 0, 1, 1]],
|
|
||||||
[[ -1, 1, 1],[ 0, 1, 1]],
|
|
||||||
[[ -1, 1, 1],[ 0, 1, 1]],
|
|
||||||
[[ -1, 1, 1],[ 0, 1, 1]],
|
|
||||||
[[ -1, 1, 1],[ 0, 1, 1]],
|
|
||||||
[[ -1, 1, 1],[ 0, 1, 1]],
|
|
||||||
[[ 1, 1, -1],[ 0, 1, 1]],
|
|
||||||
[[ 1, 1, -1],[ 0, 1, 1]],
|
|
||||||
[[ 1, 1, -1],[ 0, 1, 1]],
|
|
||||||
[[ 1, 1, -1],[ 0, 1, 1]],
|
|
||||||
[[ 1, 1, -1],[ 0, 1, 1]],
|
|
||||||
[[ 1, 1, -1],[ 0, 1, 1]]],dtype='float'),
|
|
||||||
'directions': np.array([
|
|
||||||
[[ -1, 0, 1],[ -1, -1, 1]],
|
|
||||||
[[ -1, 0, 1],[ -1, 1, -1]],
|
|
||||||
[[ 0, 1, -1],[ -1, -1, 1]],
|
|
||||||
[[ 0, 1, -1],[ -1, 1, -1]],
|
|
||||||
[[ 1, -1, 0],[ -1, -1, 1]],
|
|
||||||
[[ 1, -1, 0],[ -1, 1, -1]],
|
|
||||||
[[ 1, 0, -1],[ -1, -1, 1]],
|
|
||||||
[[ 1, 0, -1],[ -1, 1, -1]],
|
|
||||||
[[ -1, -1, 0],[ -1, -1, 1]],
|
|
||||||
[[ -1, -1, 0],[ -1, 1, -1]],
|
|
||||||
[[ 0, 1, 1],[ -1, -1, 1]],
|
|
||||||
[[ 0, 1, 1],[ -1, 1, -1]],
|
|
||||||
[[ 0, -1, 1],[ -1, -1, 1]],
|
|
||||||
[[ 0, -1, 1],[ -1, 1, -1]],
|
|
||||||
[[ -1, 0, -1],[ -1, -1, 1]],
|
|
||||||
[[ -1, 0, -1],[ -1, 1, -1]],
|
|
||||||
[[ 1, 1, 0],[ -1, -1, 1]],
|
|
||||||
[[ 1, 1, 0],[ -1, 1, -1]],
|
|
||||||
[[ -1, 1, 0],[ -1, -1, 1]],
|
|
||||||
[[ -1, 1, 0],[ -1, 1, -1]],
|
|
||||||
[[ 0, -1, -1],[ -1, -1, 1]],
|
|
||||||
[[ 0, -1, -1],[ -1, 1, -1]],
|
|
||||||
[[ 1, 0, 1],[ -1, -1, 1]],
|
|
||||||
[[ 1, 0, 1],[ -1, 1, -1]]],dtype='float')}
|
|
||||||
|
|
||||||
# Greninger--Troiano orientation relationship for fcc <-> bcc transformation
|
|
||||||
# from Y. He et al., Journal of Applied Crystallography 39:72-81, 2006
|
|
||||||
_GT = {'mapping':{'fcc':0,'bcc':1},
|
|
||||||
'planes': np.array([
|
|
||||||
[[ 1, 1, 1],[ 1, 0, 1]],
|
|
||||||
[[ 1, 1, 1],[ 1, 1, 0]],
|
|
||||||
[[ 1, 1, 1],[ 0, 1, 1]],
|
|
||||||
[[ -1, -1, 1],[ -1, 0, 1]],
|
|
||||||
[[ -1, -1, 1],[ -1, -1, 0]],
|
|
||||||
[[ -1, -1, 1],[ 0, -1, 1]],
|
|
||||||
[[ -1, 1, 1],[ -1, 0, 1]],
|
|
||||||
[[ -1, 1, 1],[ -1, 1, 0]],
|
|
||||||
[[ -1, 1, 1],[ 0, 1, 1]],
|
|
||||||
[[ 1, -1, 1],[ 1, 0, 1]],
|
|
||||||
[[ 1, -1, 1],[ 1, -1, 0]],
|
|
||||||
[[ 1, -1, 1],[ 0, -1, 1]],
|
|
||||||
[[ 1, 1, 1],[ 1, 1, 0]],
|
|
||||||
[[ 1, 1, 1],[ 0, 1, 1]],
|
|
||||||
[[ 1, 1, 1],[ 1, 0, 1]],
|
|
||||||
[[ -1, -1, 1],[ -1, -1, 0]],
|
|
||||||
[[ -1, -1, 1],[ 0, -1, 1]],
|
|
||||||
[[ -1, -1, 1],[ -1, 0, 1]],
|
|
||||||
[[ -1, 1, 1],[ -1, 1, 0]],
|
|
||||||
[[ -1, 1, 1],[ 0, 1, 1]],
|
|
||||||
[[ -1, 1, 1],[ -1, 0, 1]],
|
|
||||||
[[ 1, -1, 1],[ 1, -1, 0]],
|
|
||||||
[[ 1, -1, 1],[ 0, -1, 1]],
|
|
||||||
[[ 1, -1, 1],[ 1, 0, 1]]],dtype='float'),
|
|
||||||
'directions': np.array([
|
|
||||||
[[ -5,-12, 17],[-17, -7, 17]],
|
|
||||||
[[ 17, -5,-12],[ 17,-17, -7]],
|
|
||||||
[[-12, 17, -5],[ -7, 17,-17]],
|
|
||||||
[[ 5, 12, 17],[ 17, 7, 17]],
|
|
||||||
[[-17, 5,-12],[-17, 17, -7]],
|
|
||||||
[[ 12,-17, -5],[ 7,-17,-17]],
|
|
||||||
[[ -5, 12,-17],[-17, 7,-17]],
|
|
||||||
[[ 17, 5, 12],[ 17, 17, 7]],
|
|
||||||
[[-12,-17, 5],[ -7,-17, 17]],
|
|
||||||
[[ 5,-12,-17],[ 17, -7,-17]],
|
|
||||||
[[-17, -5, 12],[-17,-17, 7]],
|
|
||||||
[[ 12, 17, 5],[ 7, 17, 17]],
|
|
||||||
[[ -5, 17,-12],[-17, 17, -7]],
|
|
||||||
[[-12, -5, 17],[ -7,-17, 17]],
|
|
||||||
[[ 17,-12, -5],[ 17, -7,-17]],
|
|
||||||
[[ 5,-17,-12],[ 17,-17, -7]],
|
|
||||||
[[ 12, 5, 17],[ 7, 17, 17]],
|
|
||||||
[[-17, 12, -5],[-17, 7,-17]],
|
|
||||||
[[ -5,-17, 12],[-17,-17, 7]],
|
|
||||||
[[-12, 5,-17],[ -7, 17,-17]],
|
|
||||||
[[ 17, 12, 5],[ 17, 7, 17]],
|
|
||||||
[[ 5, 17, 12],[ 17, 17, 7]],
|
|
||||||
[[ 12, -5,-17],[ 7,-17,-17]],
|
|
||||||
[[-17,-12, 5],[-17,-7, 17]]],dtype='float')}
|
|
||||||
|
|
||||||
# Greninger--Troiano' orientation relationship for fcc <-> bcc transformation
|
|
||||||
# from Y. He et al., Journal of Applied Crystallography 39:72-81, 2006
|
|
||||||
_GTprime = {'mapping':{'fcc':0,'bcc':1},
|
|
||||||
'planes': np.array([
|
|
||||||
[[ 7, 17, 17],[ 12, 5, 17]],
|
|
||||||
[[ 17, 7, 17],[ 17, 12, 5]],
|
|
||||||
[[ 17, 17, 7],[ 5, 17, 12]],
|
|
||||||
[[ -7,-17, 17],[-12, -5, 17]],
|
|
||||||
[[-17, -7, 17],[-17,-12, 5]],
|
|
||||||
[[-17,-17, 7],[ -5,-17, 12]],
|
|
||||||
[[ 7,-17,-17],[ 12, -5,-17]],
|
|
||||||
[[ 17, -7,-17],[ 17,-12, -5]],
|
|
||||||
[[ 17,-17, -7],[ 5,-17,-12]],
|
|
||||||
[[ -7, 17,-17],[-12, 5,-17]],
|
|
||||||
[[-17, 7,-17],[-17, 12, -5]],
|
|
||||||
[[-17, 17, -7],[ -5, 17,-12]],
|
|
||||||
[[ 7, 17, 17],[ 12, 17, 5]],
|
|
||||||
[[ 17, 7, 17],[ 5, 12, 17]],
|
|
||||||
[[ 17, 17, 7],[ 17, 5, 12]],
|
|
||||||
[[ -7,-17, 17],[-12,-17, 5]],
|
|
||||||
[[-17, -7, 17],[ -5,-12, 17]],
|
|
||||||
[[-17,-17, 7],[-17, -5, 12]],
|
|
||||||
[[ 7,-17,-17],[ 12,-17, -5]],
|
|
||||||
[[ 17, -7,-17],[ 5, -12,-17]],
|
|
||||||
[[ 17,-17, -7],[ 17, -5,-12]],
|
|
||||||
[[ -7, 17,-17],[-12, 17, -5]],
|
|
||||||
[[-17, 7,-17],[ -5, 12,-17]],
|
|
||||||
[[-17, 17, -7],[-17, 5,-12]]],dtype='float'),
|
|
||||||
'directions': np.array([
|
|
||||||
[[ 0, 1, -1],[ 1, 1, -1]],
|
|
||||||
[[ -1, 0, 1],[ -1, 1, 1]],
|
|
||||||
[[ 1, -1, 0],[ 1, -1, 1]],
|
|
||||||
[[ 0, -1, -1],[ -1, -1, -1]],
|
|
||||||
[[ 1, 0, 1],[ 1, -1, 1]],
|
|
||||||
[[ 1, -1, 0],[ 1, -1, -1]],
|
|
||||||
[[ 0, 1, -1],[ -1, 1, -1]],
|
|
||||||
[[ 1, 0, 1],[ 1, 1, 1]],
|
|
||||||
[[ -1, -1, 0],[ -1, -1, 1]],
|
|
||||||
[[ 0, -1, -1],[ 1, -1, -1]],
|
|
||||||
[[ -1, 0, 1],[ -1, -1, 1]],
|
|
||||||
[[ -1, -1, 0],[ -1, -1, -1]],
|
|
||||||
[[ 0, -1, 1],[ 1, -1, 1]],
|
|
||||||
[[ 1, 0, -1],[ 1, 1, -1]],
|
|
||||||
[[ -1, 1, 0],[ -1, 1, 1]],
|
|
||||||
[[ 0, 1, 1],[ -1, 1, 1]],
|
|
||||||
[[ -1, 0, -1],[ -1, -1, -1]],
|
|
||||||
[[ -1, 1, 0],[ -1, 1, -1]],
|
|
||||||
[[ 0, -1, 1],[ -1, -1, 1]],
|
|
||||||
[[ -1, 0, -1],[ -1, 1, -1]],
|
|
||||||
[[ 1, 1, 0],[ 1, 1, 1]],
|
|
||||||
[[ 0, 1, 1],[ 1, 1, 1]],
|
|
||||||
[[ 1, 0, -1],[ 1, -1, -1]],
|
|
||||||
[[ 1, 1, 0],[ 1, 1, -1]]],dtype='float')}
|
|
||||||
|
|
||||||
# Nishiyama--Wassermann orientation relationship for fcc <-> bcc transformation
|
|
||||||
# from H. Kitahara et al., Materials Characterization 54:378-386, 2005
|
|
||||||
_NW = {'mapping':{'fcc':0,'bcc':1},
|
|
||||||
'planes': np.array([
|
|
||||||
[[ 1, 1, 1],[ 0, 1, 1]],
|
|
||||||
[[ 1, 1, 1],[ 0, 1, 1]],
|
|
||||||
[[ 1, 1, 1],[ 0, 1, 1]],
|
|
||||||
[[ -1, 1, 1],[ 0, 1, 1]],
|
|
||||||
[[ -1, 1, 1],[ 0, 1, 1]],
|
|
||||||
[[ -1, 1, 1],[ 0, 1, 1]],
|
|
||||||
[[ 1, -1, 1],[ 0, 1, 1]],
|
|
||||||
[[ 1, -1, 1],[ 0, 1, 1]],
|
|
||||||
[[ 1, -1, 1],[ 0, 1, 1]],
|
|
||||||
[[ -1, -1, 1],[ 0, 1, 1]],
|
|
||||||
[[ -1, -1, 1],[ 0, 1, 1]],
|
|
||||||
[[ -1, -1, 1],[ 0, 1, 1]]],dtype='float'),
|
|
||||||
'directions': np.array([
|
|
||||||
[[ 2, -1, -1],[ 0, -1, 1]],
|
|
||||||
[[ -1, 2, -1],[ 0, -1, 1]],
|
|
||||||
[[ -1, -1, 2],[ 0, -1, 1]],
|
|
||||||
[[ -2, -1, -1],[ 0, -1, 1]],
|
|
||||||
[[ 1, 2, -1],[ 0, -1, 1]],
|
|
||||||
[[ 1, -1, 2],[ 0, -1, 1]],
|
|
||||||
[[ 2, 1, -1],[ 0, -1, 1]],
|
|
||||||
[[ -1, -2, -1],[ 0, -1, 1]],
|
|
||||||
[[ -1, 1, 2],[ 0, -1, 1]],
|
|
||||||
[[ 2, -1, 1],[ 0, -1, 1]], #It is wrong in the paper, but matrix is correct
|
|
||||||
[[ -1, 2, 1],[ 0, -1, 1]],
|
|
||||||
[[ -1, -1, -2],[ 0, -1, 1]]],dtype='float')}
|
|
||||||
|
|
||||||
# Pitsch orientation relationship for fcc <-> bcc transformation
|
|
||||||
# from Y. He et al., Acta Materialia 53:1179-1190, 2005
|
|
||||||
_Pitsch = {'mapping':{'fcc':0,'bcc':1},
|
|
||||||
'planes': np.array([
|
|
||||||
[[ 0, 1, 0],[ -1, 0, 1]],
|
|
||||||
[[ 0, 0, 1],[ 1, -1, 0]],
|
|
||||||
[[ 1, 0, 0],[ 0, 1, -1]],
|
|
||||||
[[ 1, 0, 0],[ 0, -1, -1]],
|
|
||||||
[[ 0, 1, 0],[ -1, 0, -1]],
|
|
||||||
[[ 0, 0, 1],[ -1, -1, 0]],
|
|
||||||
[[ 0, 1, 0],[ -1, 0, -1]],
|
|
||||||
[[ 0, 0, 1],[ -1, -1, 0]],
|
|
||||||
[[ 1, 0, 0],[ 0, -1, -1]],
|
|
||||||
[[ 1, 0, 0],[ 0, -1, 1]],
|
|
||||||
[[ 0, 1, 0],[ 1, 0, -1]],
|
|
||||||
[[ 0, 0, 1],[ -1, 1, 0]]],dtype='float'),
|
|
||||||
'directions': np.array([
|
|
||||||
[[ 1, 0, 1],[ 1, -1, 1]],
|
|
||||||
[[ 1, 1, 0],[ 1, 1, -1]],
|
|
||||||
[[ 0, 1, 1],[ -1, 1, 1]],
|
|
||||||
[[ 0, 1, -1],[ -1, 1, -1]],
|
|
||||||
[[ -1, 0, 1],[ -1, -1, 1]],
|
|
||||||
[[ 1, -1, 0],[ 1, -1, -1]],
|
|
||||||
[[ 1, 0, -1],[ 1, -1, -1]],
|
|
||||||
[[ -1, 1, 0],[ -1, 1, -1]],
|
|
||||||
[[ 0, -1, 1],[ -1, -1, 1]],
|
|
||||||
[[ 0, 1, 1],[ -1, 1, 1]],
|
|
||||||
[[ 1, 0, 1],[ 1, -1, 1]],
|
|
||||||
[[ 1, 1, 0],[ 1, 1, -1]]],dtype='float')}
|
|
||||||
|
|
||||||
# Bain orientation relationship for fcc <-> bcc transformation
|
|
||||||
# from Y. He et al., Journal of Applied Crystallography 39:72-81, 2006
|
|
||||||
_Bain = {'mapping':{'fcc':0,'bcc':1},
|
|
||||||
'planes': np.array([
|
|
||||||
[[ 1, 0, 0],[ 1, 0, 0]],
|
|
||||||
[[ 0, 1, 0],[ 0, 1, 0]],
|
|
||||||
[[ 0, 0, 1],[ 0, 0, 1]]],dtype='float'),
|
|
||||||
'directions': np.array([
|
|
||||||
[[ 0, 1, 0],[ 0, 1, 1]],
|
|
||||||
[[ 0, 0, 1],[ 1, 0, 1]],
|
|
||||||
[[ 1, 0, 0],[ 1, 1, 0]]],dtype='float')}
|
|
||||||
|
|
||||||
|
|
||||||
def relation_operations(self,model):
|
|
||||||
"""
|
|
||||||
Crystallographic orientation relationships for phase transformations.
|
|
||||||
|
|
||||||
References
|
|
||||||
----------
|
|
||||||
S. Morito et al., Journal of Alloys and Compounds 577:s587-s592, 2013
|
|
||||||
https://doi.org/10.1016/j.jallcom.2012.02.004
|
|
||||||
|
|
||||||
K. Kitahara et al., Acta Materialia 54(5):1279-1288, 2006
|
|
||||||
https://doi.org/10.1016/j.actamat.2005.11.001
|
|
||||||
|
|
||||||
Y. He et al., Journal of Applied Crystallography 39:72-81, 2006
|
|
||||||
https://doi.org/10.1107/S0021889805038276
|
|
||||||
|
|
||||||
H. Kitahara et al., Materials Characterization 54(4-5):378-386, 2005
|
|
||||||
https://doi.org/10.1016/j.matchar.2004.12.015
|
|
||||||
|
|
||||||
Y. He et al., Acta Materialia 53(4):1179-1190, 2005
|
|
||||||
https://doi.org/10.1016/j.actamat.2004.11.021
|
|
||||||
|
|
||||||
"""
|
|
||||||
models={'KS':self._KS, 'GT':self._GT, 'GT_prime':self._GTprime,
|
|
||||||
'NW':self._NW, 'Pitsch': self._Pitsch, 'Bain':self._Bain}
|
|
||||||
try:
|
|
||||||
relationship = models[model]
|
|
||||||
except KeyError :
|
|
||||||
raise KeyError(f'Orientation relationship "{model}" is unknown')
|
|
||||||
|
|
||||||
if self.lattice not in relationship['mapping']:
|
|
||||||
raise ValueError(f'Relationship "{model}" not supported for lattice "{self.lattice}"')
|
|
||||||
|
|
||||||
r = {'lattice':Lattice((set(relationship['mapping'])-{self.lattice}).pop()), # target lattice
|
|
||||||
'rotations':[] }
|
|
||||||
|
|
||||||
myPlane_id = relationship['mapping'][self.lattice]
|
|
||||||
otherPlane_id = (myPlane_id+1)%2
|
|
||||||
myDir_id = myPlane_id +2
|
|
||||||
otherDir_id = otherPlane_id +2
|
|
||||||
|
|
||||||
for miller in np.hstack((relationship['planes'],relationship['directions'])):
|
|
||||||
myPlane = miller[myPlane_id]/ np.linalg.norm(miller[myPlane_id])
|
|
||||||
myDir = miller[myDir_id]/ np.linalg.norm(miller[myDir_id])
|
|
||||||
myMatrix = np.array([myDir,np.cross(myPlane,myDir),myPlane])
|
|
||||||
|
|
||||||
otherPlane = miller[otherPlane_id]/ np.linalg.norm(miller[otherPlane_id])
|
|
||||||
otherDir = miller[otherDir_id]/ np.linalg.norm(miller[otherDir_id])
|
|
||||||
otherMatrix = np.array([otherDir,np.cross(otherPlane,otherDir),otherPlane])
|
|
||||||
|
|
||||||
r['rotations'].append(np.dot(otherMatrix.T,myMatrix))
|
|
||||||
|
|
||||||
r['rotations'] = np.array(r['rotations'])
|
|
||||||
|
|
||||||
return r
|
|
File diff suppressed because it is too large
Load Diff
|
@ -15,7 +15,6 @@ from numpy.lib import recfunctions as rfn
|
||||||
import damask
|
import damask
|
||||||
from . import VTK
|
from . import VTK
|
||||||
from . import Table
|
from . import Table
|
||||||
from . import Rotation
|
|
||||||
from . import Orientation
|
from . import Orientation
|
||||||
from . import grid_filters
|
from . import grid_filters
|
||||||
from . import mechanics
|
from . import mechanics
|
||||||
|
@ -743,11 +742,13 @@ class Result:
|
||||||
def _add_IPF_color(q,l):
|
def _add_IPF_color(q,l):
|
||||||
m = util.scale_to_coprime(np.array(l))
|
m = util.scale_to_coprime(np.array(l))
|
||||||
|
|
||||||
o = Orientation(Rotation(rfn.structured_to_unstructured(q['data'])),
|
o = Orientation(rotation = (rfn.structured_to_unstructured(q['data'])),
|
||||||
lattice = q['meta']['Lattice'])
|
lattice = {'fcc':'cF',
|
||||||
|
'bcc':'cI',
|
||||||
|
'hex':'hP'}[q['meta']['Lattice']])
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'data': np.uint8(o.IPF_color(l)*255),
|
'data': np.uint8(o.IPF_color(o.to_SST(l))*255),
|
||||||
'label': 'IPFcolor_[{} {} {}]'.format(*m),
|
'label': 'IPFcolor_[{} {} {}]'.format(*m),
|
||||||
'meta' : {
|
'meta' : {
|
||||||
'Unit': '8-bit RGB',
|
'Unit': '8-bit RGB',
|
||||||
|
@ -897,42 +898,47 @@ class Result:
|
||||||
self._add_generic_pointwise(self._add_PK2,{'P':P,'F':F})
|
self._add_generic_pointwise(self._add_PK2,{'P':P,'F':F})
|
||||||
|
|
||||||
|
|
||||||
@staticmethod
|
# The add_pole functionality needs discussion.
|
||||||
def _add_pole(q,p,polar):
|
# The new Crystal object can perform such a calculation but the outcome depends on the lattice parameters
|
||||||
pole = np.array(p)
|
# as well as on whether a direction or plane is concerned (see the DAMASK_examples/pole_figure notebook).
|
||||||
unit_pole = pole/np.linalg.norm(pole)
|
# Below code appears to be too simplistic.
|
||||||
m = util.scale_to_coprime(pole)
|
|
||||||
rot = Rotation(q['data'].view(np.double).reshape(-1,4))
|
|
||||||
|
|
||||||
rotatedPole = rot @ np.broadcast_to(unit_pole,rot.shape+(3,)) # rotate pole according to crystal orientation
|
# @staticmethod
|
||||||
xy = rotatedPole[:,0:2]/(1.+abs(unit_pole[2])) # stereographic projection
|
# def _add_pole(q,p,polar):
|
||||||
coords = xy if not polar else \
|
# pole = np.array(p)
|
||||||
np.block([np.sqrt(xy[:,0:1]*xy[:,0:1]+xy[:,1:2]*xy[:,1:2]),np.arctan2(xy[:,1:2],xy[:,0:1])])
|
# unit_pole = pole/np.linalg.norm(pole)
|
||||||
return {
|
# m = util.scale_to_coprime(pole)
|
||||||
'data': coords,
|
# rot = Rotation(q['data'].view(np.double).reshape(-1,4))
|
||||||
'label': 'p^{}_[{} {} {})'.format(u'rφ' if polar else 'xy',*m),
|
#
|
||||||
'meta' : {
|
# rotatedPole = rot @ np.broadcast_to(unit_pole,rot.shape+(3,)) # rotate pole according to crystal orientation
|
||||||
'Unit': '1',
|
# xy = rotatedPole[:,0:2]/(1.+abs(unit_pole[2])) # stereographic projection
|
||||||
'Description': '{} coordinates of stereographic projection of pole (direction/plane) in crystal frame'\
|
# coords = xy if not polar else \
|
||||||
.format('Polar' if polar else 'Cartesian'),
|
# np.block([np.sqrt(xy[:,0:1]*xy[:,0:1]+xy[:,1:2]*xy[:,1:2]),np.arctan2(xy[:,1:2],xy[:,0:1])])
|
||||||
'Creator': 'add_pole'
|
# return {
|
||||||
}
|
# 'data': coords,
|
||||||
}
|
# 'label': 'p^{}_[{} {} {})'.format(u'rφ' if polar else 'xy',*m),
|
||||||
def add_pole(self,q,p,polar=False):
|
# 'meta' : {
|
||||||
"""
|
# 'Unit': '1',
|
||||||
Add coordinates of stereographic projection of given pole in crystal frame.
|
# 'Description': '{} coordinates of stereographic projection of pole (direction/plane) in crystal frame'\
|
||||||
|
# .format('Polar' if polar else 'Cartesian'),
|
||||||
Parameters
|
# 'Creator': 'add_pole'
|
||||||
----------
|
# }
|
||||||
q : str
|
# }
|
||||||
Label of the dataset containing the crystallographic orientation as quaternions.
|
# def add_pole(self,q,p,polar=False):
|
||||||
p : numpy.array of shape (3)
|
# """
|
||||||
Crystallographic direction or plane.
|
# Add coordinates of stereographic projection of given pole in crystal frame.
|
||||||
polar : bool, optional
|
#
|
||||||
Give pole in polar coordinates. Defaults to False.
|
# Parameters
|
||||||
|
# ----------
|
||||||
"""
|
# q : str
|
||||||
self._add_generic_pointwise(self._add_pole,{'q':q},{'p':p,'polar':polar})
|
# Label of the dataset containing the crystallographic orientation as quaternions.
|
||||||
|
# p : numpy.array of shape (3)
|
||||||
|
# Crystallographic direction or plane.
|
||||||
|
# polar : bool, optional
|
||||||
|
# Give pole in polar coordinates. Defaults to False.
|
||||||
|
#
|
||||||
|
# """
|
||||||
|
# self._add_generic_pointwise(self._add_pole,{'q':q},{'p':p,'polar':polar})
|
||||||
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
|
|
@ -13,18 +13,18 @@ _R1 = (3.*np.pi/4.)**(1./3.)
|
||||||
|
|
||||||
class Rotation:
|
class Rotation:
|
||||||
u"""
|
u"""
|
||||||
Orientation stored with functionality for conversion to different representations.
|
Rotation with functionality for conversion between different representations.
|
||||||
|
|
||||||
The following conventions apply:
|
The following conventions apply:
|
||||||
|
|
||||||
- coordinate frames are right-handed.
|
- Coordinate frames are right-handed.
|
||||||
- a rotation angle ω is taken to be positive for a counterclockwise rotation
|
- A rotation angle ω is taken to be positive for a counterclockwise rotation
|
||||||
when viewing from the end point of the rotation axis towards the origin.
|
when viewing from the end point of the rotation axis towards the origin.
|
||||||
- rotations will be interpreted in the passive sense.
|
- Rotations will be interpreted in the passive sense.
|
||||||
- Euler angle triplets are implemented using the Bunge convention,
|
- Euler angle triplets are implemented using the Bunge convention,
|
||||||
with the angular ranges as [0,2π], [0,π], [0,2π].
|
with angular ranges of [0,2π], [0,π], [0,2π].
|
||||||
- the rotation angle ω is limited to the interval [0,π].
|
- The rotation angle ω is limited to the interval [0,π].
|
||||||
- the real part of a quaternion is positive, Re(q) > 0
|
- The real part of a quaternion is positive, Re(q) > 0
|
||||||
- P = -1 (as default).
|
- P = -1 (as default).
|
||||||
|
|
||||||
Examples
|
Examples
|
||||||
|
@ -33,7 +33,7 @@ class Rotation:
|
||||||
coordinates "b" expressed in system "B":
|
coordinates "b" expressed in system "B":
|
||||||
|
|
||||||
- b = Q @ a
|
- b = Q @ a
|
||||||
- b = np.dot(Q.asMatrix(),a)
|
- b = np.dot(Q.as_matrix(),a)
|
||||||
|
|
||||||
References
|
References
|
||||||
----------
|
----------
|
||||||
|
@ -44,20 +44,83 @@ class Rotation:
|
||||||
|
|
||||||
__slots__ = ['quaternion']
|
__slots__ = ['quaternion']
|
||||||
|
|
||||||
def __init__(self,quaternion = np.array([1.0,0.0,0.0,0.0])):
|
def __init__(self,rotation = np.array([1.0,0.0,0.0,0.0])):
|
||||||
"""
|
"""
|
||||||
Initializes to identity unless specified.
|
Initialize rotation object.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
quaternion : numpy.ndarray, optional
|
rotation : list, numpy.ndarray, Rotation, optional
|
||||||
Unit quaternion in positive real hemisphere.
|
Unit quaternion in positive real hemisphere.
|
||||||
Use .from_quaternion to perform a sanity check.
|
Use .from_quaternion to perform a sanity check.
|
||||||
|
Defaults to no rotation.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if quaternion.shape[-1] != 4:
|
if isinstance(rotation,Rotation):
|
||||||
raise ValueError('Not a quaternion')
|
self.quaternion = rotation.quaternion.copy()
|
||||||
self.quaternion = quaternion.copy()
|
elif np.array(rotation).shape[-1] == 4:
|
||||||
|
self.quaternion = np.array(rotation)
|
||||||
|
else:
|
||||||
|
raise ValueError('"rotation" is neither a Rotation nor a quaternion')
|
||||||
|
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
"""Represent rotation as unit quaternion, rotation matrix, and Bunge-Euler angles."""
|
||||||
|
return 'Quaternions:\n'+str(self.quaternion) \
|
||||||
|
if self.quaternion.shape != (4,) else \
|
||||||
|
'\n'.join([
|
||||||
|
'Quaternion: (real={:.3f}, imag=<{:+.3f}, {:+.3f}, {:+.3f}>)'.format(*(self.quaternion)),
|
||||||
|
'Matrix:\n{}'.format(np.round(self.as_matrix(),8)),
|
||||||
|
'Bunge Eulers / deg: ({:3.2f}, {:3.2f}, {:3.2f})'.format(*self.as_Eulers(degrees=True)),
|
||||||
|
])
|
||||||
|
|
||||||
|
|
||||||
|
# ToDo: Check difference __copy__ vs __deepcopy__
|
||||||
|
def __copy__(self,**kwargs):
|
||||||
|
"""Copy."""
|
||||||
|
return self.__class__(rotation=kwargs['rotation'] if 'rotation' in kwargs else self.quaternion)
|
||||||
|
|
||||||
|
copy = __copy__
|
||||||
|
|
||||||
|
|
||||||
|
def __getitem__(self,item):
|
||||||
|
"""Return slice according to item."""
|
||||||
|
return self.copy() \
|
||||||
|
if self.shape == () else \
|
||||||
|
self.copy(rotation=self.quaternion[item+(slice(None),)] if isinstance(item,tuple) else self.quaternion[item])
|
||||||
|
|
||||||
|
|
||||||
|
def __eq__(self,other):
|
||||||
|
"""
|
||||||
|
Equal to other.
|
||||||
|
|
||||||
|
Equality is determined taking limited floating point precision into
|
||||||
|
account. See numpy.allclose for details.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
other : Rotation
|
||||||
|
Rotation to check for equality.
|
||||||
|
|
||||||
|
"""
|
||||||
|
return np.prod(self.shape,dtype=int) == np.prod(other.shape,dtype=int) \
|
||||||
|
and np.allclose(self.quaternion,other.quaternion)
|
||||||
|
|
||||||
|
|
||||||
|
def __neq__(self,other):
|
||||||
|
"""
|
||||||
|
Not Equal to other.
|
||||||
|
|
||||||
|
Equality is determined taking limited floating point precision into
|
||||||
|
account. See numpy.allclose for details.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
other : Rotation
|
||||||
|
Rotation to check for inequality.
|
||||||
|
|
||||||
|
"""
|
||||||
|
return not self.__eq__(other)
|
||||||
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
@ -65,38 +128,35 @@ class Rotation:
|
||||||
return self.quaternion.shape[:-1]
|
return self.quaternion.shape[:-1]
|
||||||
|
|
||||||
|
|
||||||
# ToDo: Check difference __copy__ vs __deepcopy__
|
|
||||||
def __copy__(self):
|
|
||||||
"""Copy."""
|
|
||||||
return self.__class__(self.quaternion)
|
|
||||||
|
|
||||||
copy = __copy__
|
|
||||||
|
|
||||||
|
|
||||||
def __repr__(self):
|
|
||||||
"""Orientation displayed as unit quaternion, rotation matrix, and Bunge-Euler angles."""
|
|
||||||
if self.quaternion.shape != (4,):
|
|
||||||
return 'Quaternions:\n'+str(self.quaternion) # ToDo: could be nicer ...
|
|
||||||
return '\n'.join([
|
|
||||||
'Quaternion: (real={:.3f}, imag=<{:+.3f}, {:+.3f}, {:+.3f}>)'.format(*(self.quaternion)),
|
|
||||||
'Matrix:\n{}'.format(np.round(self.as_matrix(),8)),
|
|
||||||
'Bunge Eulers / deg: ({:3.2f}, {:3.2f}, {:3.2f})'.format(*self.as_Eulers(degrees=True)),
|
|
||||||
])
|
|
||||||
|
|
||||||
|
|
||||||
def __getitem__(self,item):
|
|
||||||
"""Iterate over leading/leftmost dimension of Rotation array."""
|
|
||||||
if self.shape == (): return self.copy()
|
|
||||||
if isinstance(item,tuple) and len(item) >= len(self):
|
|
||||||
raise IndexError('Too many indices')
|
|
||||||
return self.__class__(self.quaternion[item])
|
|
||||||
|
|
||||||
|
|
||||||
def __len__(self):
|
def __len__(self):
|
||||||
"""Length of leading/leftmost dimension of Rotation array."""
|
"""Length of leading/leftmost dimension of Rotation array."""
|
||||||
return 0 if self.shape == () else self.shape[0]
|
return 0 if self.shape == () else self.shape[0]
|
||||||
|
|
||||||
|
|
||||||
|
def __invert__(self):
|
||||||
|
"""Inverse rotation (backward rotation)."""
|
||||||
|
dup = self.copy()
|
||||||
|
dup.quaternion[...,1:] *= -1
|
||||||
|
return dup
|
||||||
|
|
||||||
|
|
||||||
|
def __pow__(self,pwr):
|
||||||
|
"""
|
||||||
|
Raise quaternion to power.
|
||||||
|
|
||||||
|
Equivalent to performing the rotation 'pwr' times.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
pwr : float
|
||||||
|
Power to raise quaternion to.
|
||||||
|
|
||||||
|
"""
|
||||||
|
phi = np.arccos(self.quaternion[...,0:1])
|
||||||
|
p = self.quaternion[...,1:]/np.linalg.norm(self.quaternion[...,1:],axis=-1,keepdims=True)
|
||||||
|
return self.copy(rotation=Rotation(np.block([np.cos(pwr*phi),np.sin(pwr*phi)*p]))._standardize())
|
||||||
|
|
||||||
|
|
||||||
def __matmul__(self,other):
|
def __matmul__(self,other):
|
||||||
"""
|
"""
|
||||||
Rotation of vector, second or fourth order tensor, or rotation object.
|
Rotation of vector, second or fourth order tensor, or rotation object.
|
||||||
|
@ -119,7 +179,7 @@ class Rotation:
|
||||||
p_o = other.quaternion[...,1:]
|
p_o = other.quaternion[...,1:]
|
||||||
q = (q_m*q_o - np.einsum('...i,...i',p_m,p_o).reshape(self.shape+(1,)))
|
q = (q_m*q_o - np.einsum('...i,...i',p_m,p_o).reshape(self.shape+(1,)))
|
||||||
p = q_m*p_o + q_o*p_m + _P * np.cross(p_m,p_o)
|
p = q_m*p_o + q_o*p_m + _P * np.cross(p_m,p_o)
|
||||||
return self.__class__(np.block([q,p]))._standardize()
|
return Rotation(np.block([q,p]))._standardize()
|
||||||
|
|
||||||
elif isinstance(other,np.ndarray):
|
elif isinstance(other,np.ndarray):
|
||||||
if self.shape + (3,) == other.shape:
|
if self.shape + (3,) == other.shape:
|
||||||
|
@ -146,27 +206,89 @@ class Rotation:
|
||||||
|
|
||||||
|
|
||||||
def _standardize(self):
|
def _standardize(self):
|
||||||
"""Standardize (ensure positive real hemisphere)."""
|
"""Standardize quaternion (ensure positive real hemisphere)."""
|
||||||
self.quaternion[self.quaternion[...,0] < 0.0] *= -1
|
self.quaternion[self.quaternion[...,0] < 0.0] *= -1
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def inverse(self):
|
|
||||||
"""In-place inverse rotation (backward rotation)."""
|
|
||||||
self.quaternion[...,1:] *= -1
|
|
||||||
return self
|
|
||||||
|
|
||||||
def __invert__(self):
|
def append(self,other):
|
||||||
"""Inverse rotation (backward rotation)."""
|
"""Extend rotation array along first dimension with other array."""
|
||||||
return self.copy().inverse()
|
return self.copy(rotation=np.vstack((self.quaternion,other.quaternion)))
|
||||||
|
|
||||||
def inversed(self):
|
|
||||||
"""Inverse rotation (backward rotation)."""
|
def flatten(self,order = 'C'):
|
||||||
return ~ self
|
"""Flatten quaternion array."""
|
||||||
|
return self.copy(rotation=self.quaternion.reshape((-1,4),order=order))
|
||||||
|
|
||||||
|
|
||||||
|
def reshape(self,shape,order = 'C'):
|
||||||
|
"""Reshape quaternion array."""
|
||||||
|
if isinstance(shape,(int,np.integer)): shape = (shape,)
|
||||||
|
return self.copy(rotation=self.quaternion.reshape(tuple(shape)+(4,),order=order))
|
||||||
|
|
||||||
|
|
||||||
|
def broadcast_to(self,shape,mode = 'right'):
|
||||||
|
"""
|
||||||
|
Broadcast quaternion array to shape.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
shape : tuple
|
||||||
|
Shape of broadcasted array.
|
||||||
|
mode : str, optional
|
||||||
|
Where to preferentially locate missing dimensions.
|
||||||
|
Either 'left' or 'right' (default).
|
||||||
|
|
||||||
|
"""
|
||||||
|
if isinstance(shape,(int,np.integer)): shape = (shape,)
|
||||||
|
return self.copy(rotation=np.broadcast_to(self.quaternion.reshape(util.shapeshifter(self.shape,shape,mode)+(4,)),
|
||||||
|
shape+(4,)))
|
||||||
|
|
||||||
|
|
||||||
|
def average(self,weights = None):
|
||||||
|
"""
|
||||||
|
Average rotations along last dimension.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
weights : list of floats, optional
|
||||||
|
Relative weight of each rotation.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
average : Rotation
|
||||||
|
Weighted average of original Rotation field.
|
||||||
|
|
||||||
|
References
|
||||||
|
----------
|
||||||
|
Quaternion averaging
|
||||||
|
F. Landis Markley, Yang Cheng, John L. Crassidis, Yaakov Oshman
|
||||||
|
Journal of Guidance, Control, and Dynamics 30(4):1193-1197, 2007
|
||||||
|
10.2514/1.28949
|
||||||
|
|
||||||
|
"""
|
||||||
|
def _M(quat):
|
||||||
|
"""Intermediate representation supporting quaternion averaging."""
|
||||||
|
return np.einsum('...i,...j',quat,quat)
|
||||||
|
|
||||||
|
if not weights:
|
||||||
|
weights = np.ones(self.shape,dtype=float)
|
||||||
|
|
||||||
|
eig, vec = np.linalg.eig(np.sum(_M(self.quaternion) * weights[...,np.newaxis,np.newaxis],axis=-3) \
|
||||||
|
/np.sum( weights[...,np.newaxis,np.newaxis],axis=-3))
|
||||||
|
|
||||||
|
return Rotation.from_quaternion(np.real(
|
||||||
|
np.squeeze(
|
||||||
|
np.take_along_axis(vec,
|
||||||
|
eig.argmax(axis=-1)[...,np.newaxis,np.newaxis],
|
||||||
|
axis=-1),
|
||||||
|
axis=-1)),
|
||||||
|
accept_homomorph = True)
|
||||||
|
|
||||||
|
|
||||||
def misorientation(self,other):
|
def misorientation(self,other):
|
||||||
"""
|
"""
|
||||||
Get Misorientation.
|
Calculate misorientation from self to other Rotation.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
|
@ -177,33 +299,6 @@ class Rotation:
|
||||||
return other@~self
|
return other@~self
|
||||||
|
|
||||||
|
|
||||||
def broadcast_to(self,shape):
|
|
||||||
if isinstance(shape,(int,np.integer)): shape = (shape,)
|
|
||||||
if self.shape == ():
|
|
||||||
q = np.broadcast_to(self.quaternion,shape+(4,))
|
|
||||||
else:
|
|
||||||
q = np.block([np.broadcast_to(self.quaternion[...,0:1],shape).reshape(shape+(1,)),
|
|
||||||
np.broadcast_to(self.quaternion[...,1:2],shape).reshape(shape+(1,)),
|
|
||||||
np.broadcast_to(self.quaternion[...,2:3],shape).reshape(shape+(1,)),
|
|
||||||
np.broadcast_to(self.quaternion[...,3:4],shape).reshape(shape+(1,))])
|
|
||||||
return self.__class__(q)
|
|
||||||
|
|
||||||
|
|
||||||
def average(self,other): #ToDo: discuss calling for vectors
|
|
||||||
"""
|
|
||||||
Calculate the average rotation.
|
|
||||||
|
|
||||||
Parameters
|
|
||||||
----------
|
|
||||||
other : Rotation
|
|
||||||
Rotation from which the average is rotated.
|
|
||||||
|
|
||||||
"""
|
|
||||||
if self.quaternion.shape != (4,) or other.quaternion.shape != (4,):
|
|
||||||
raise NotImplementedError('Support for multiple rotations missing')
|
|
||||||
return Rotation.from_average([self,other])
|
|
||||||
|
|
||||||
|
|
||||||
################################################################################################
|
################################################################################################
|
||||||
# convert to different orientation representations (numpy arrays)
|
# convert to different orientation representations (numpy arrays)
|
||||||
|
|
||||||
|
@ -326,20 +421,6 @@ class Rotation:
|
||||||
"""
|
"""
|
||||||
return Rotation._qu2cu(self.quaternion)
|
return Rotation._qu2cu(self.quaternion)
|
||||||
|
|
||||||
@property
|
|
||||||
def M(self): # ToDo not sure about the name: as_M or M? we do not have a from_M
|
|
||||||
"""
|
|
||||||
Intermediate representation supporting quaternion averaging.
|
|
||||||
|
|
||||||
References
|
|
||||||
----------
|
|
||||||
F. Landis Markley et al., Journal of Guidance, Control, and Dynamics 30(4):1193-1197, 2007
|
|
||||||
https://doi.org/10.2514/1.28949
|
|
||||||
|
|
||||||
"""
|
|
||||||
return np.einsum('...i,...j',self.quaternion,self.quaternion)
|
|
||||||
|
|
||||||
|
|
||||||
################################################################################################
|
################################################################################################
|
||||||
# Static constructors. The input data needs to follow the conventions, options allow to
|
# Static constructors. The input data needs to follow the conventions, options allow to
|
||||||
# relax the conventions.
|
# relax the conventions.
|
||||||
|
@ -347,7 +428,7 @@ class Rotation:
|
||||||
def from_quaternion(q,
|
def from_quaternion(q,
|
||||||
accept_homomorph = False,
|
accept_homomorph = False,
|
||||||
P = -1,
|
P = -1,
|
||||||
acceptHomomorph = None): # old name (for compatibility)
|
**kwargs):
|
||||||
"""
|
"""
|
||||||
Initialize from quaternion.
|
Initialize from quaternion.
|
||||||
|
|
||||||
|
@ -363,15 +444,13 @@ class Rotation:
|
||||||
Convention used. Defaults to -1.
|
Convention used. Defaults to -1.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if acceptHomomorph is not None:
|
|
||||||
accept_homomorph = acceptHomomorph # for compatibility
|
|
||||||
qu = np.array(q,dtype=float)
|
qu = np.array(q,dtype=float)
|
||||||
if qu.shape[:-2:-1] != (4,):
|
if qu.shape[:-2:-1] != (4,):
|
||||||
raise ValueError('Invalid shape.')
|
raise ValueError('Invalid shape.')
|
||||||
if abs(P) != 1:
|
if abs(P) != 1:
|
||||||
raise ValueError('P ∉ {-1,1}')
|
raise ValueError('P ∉ {-1,1}')
|
||||||
|
|
||||||
if P == 1: qu[...,1:4] *= -1
|
qu[...,1:4] *= -P
|
||||||
if accept_homomorph:
|
if accept_homomorph:
|
||||||
qu[qu[...,0] < 0.0] *= -1
|
qu[qu[...,0] < 0.0] *= -1
|
||||||
else:
|
else:
|
||||||
|
@ -384,7 +463,8 @@ class Rotation:
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def from_Eulers(phi,
|
def from_Eulers(phi,
|
||||||
degrees = False):
|
degrees = False,
|
||||||
|
**kwargs):
|
||||||
"""
|
"""
|
||||||
Initialize from Bunge-Euler angles.
|
Initialize from Bunge-Euler angles.
|
||||||
|
|
||||||
|
@ -411,7 +491,8 @@ class Rotation:
|
||||||
def from_axis_angle(axis_angle,
|
def from_axis_angle(axis_angle,
|
||||||
degrees = False,
|
degrees = False,
|
||||||
normalize = False,
|
normalize = False,
|
||||||
P = -1):
|
P = -1,
|
||||||
|
**kwargs):
|
||||||
"""
|
"""
|
||||||
Initialize from Axis angle pair.
|
Initialize from Axis angle pair.
|
||||||
|
|
||||||
|
@ -434,7 +515,7 @@ class Rotation:
|
||||||
if abs(P) != 1:
|
if abs(P) != 1:
|
||||||
raise ValueError('P ∉ {-1,1}')
|
raise ValueError('P ∉ {-1,1}')
|
||||||
|
|
||||||
if P == 1: ax[...,0:3] *= -1
|
ax[...,0:3] *= -P
|
||||||
if degrees: ax[..., 3] = np.radians(ax[...,3])
|
if degrees: ax[..., 3] = np.radians(ax[...,3])
|
||||||
if normalize: ax[...,0:3] /= np.linalg.norm(ax[...,0:3],axis=-1,keepdims=True)
|
if normalize: ax[...,0:3] /= np.linalg.norm(ax[...,0:3],axis=-1,keepdims=True)
|
||||||
if np.any(ax[...,3] < 0.0) or np.any(ax[...,3] > np.pi):
|
if np.any(ax[...,3] < 0.0) or np.any(ax[...,3] > np.pi):
|
||||||
|
@ -448,14 +529,15 @@ class Rotation:
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def from_basis(basis,
|
def from_basis(basis,
|
||||||
orthonormal = True,
|
orthonormal = True,
|
||||||
reciprocal = False):
|
reciprocal = False,
|
||||||
|
**kwargs):
|
||||||
"""
|
"""
|
||||||
Initialize from lattice basis vectors.
|
Initialize from lattice basis vectors.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
basis : numpy.ndarray of shape (...,3,3)
|
basis : numpy.ndarray of shape (...,3,3)
|
||||||
Three lattice basis vectors in three dimensions.
|
Three three-dimensional lattice basis vectors.
|
||||||
orthonormal : boolean, optional
|
orthonormal : boolean, optional
|
||||||
Basis is strictly orthonormal, i.e. is free of stretch components. Defaults to True.
|
Basis is strictly orthonormal, i.e. is free of stretch components. Defaults to True.
|
||||||
reciprocal : boolean, optional
|
reciprocal : boolean, optional
|
||||||
|
@ -463,7 +545,7 @@ class Rotation:
|
||||||
|
|
||||||
"""
|
"""
|
||||||
om = np.array(basis,dtype=float)
|
om = np.array(basis,dtype=float)
|
||||||
if om.shape[:-3:-1] != (3,3):
|
if om.shape[-2:] != (3,3):
|
||||||
raise ValueError('Invalid shape.')
|
raise ValueError('Invalid shape.')
|
||||||
|
|
||||||
if reciprocal:
|
if reciprocal:
|
||||||
|
@ -482,7 +564,7 @@ class Rotation:
|
||||||
return Rotation(Rotation._om2qu(om))
|
return Rotation(Rotation._om2qu(om))
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def from_matrix(R):
|
def from_matrix(R,**kwargs):
|
||||||
"""
|
"""
|
||||||
Initialize from rotation matrix.
|
Initialize from rotation matrix.
|
||||||
|
|
||||||
|
@ -494,10 +576,40 @@ class Rotation:
|
||||||
"""
|
"""
|
||||||
return Rotation.from_basis(R)
|
return Rotation.from_basis(R)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def from_parallel(a,b,
|
||||||
|
**kwargs):
|
||||||
|
"""
|
||||||
|
Initialize from pairs of two orthogonal lattice basis vectors.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
a : numpy.ndarray of shape (...,2,3)
|
||||||
|
Two three-dimensional lattice vectors of first orthogonal basis.
|
||||||
|
b : numpy.ndarray of shape (...,2,3)
|
||||||
|
Corresponding three-dimensional lattice vectors of second basis.
|
||||||
|
|
||||||
|
"""
|
||||||
|
a_ = np.array(a)
|
||||||
|
b_ = np.array(b)
|
||||||
|
if a_.shape[-2:] != (2,3) or b_.shape[-2:] != (2,3) or a_.shape != b_.shape:
|
||||||
|
raise ValueError('Invalid shape.')
|
||||||
|
am = np.stack([ a_[...,0,:],
|
||||||
|
a_[...,1,:],
|
||||||
|
np.cross(a_[...,0,:],a_[...,1,:]) ],axis=-2)
|
||||||
|
bm = np.stack([ b_[...,0,:],
|
||||||
|
b_[...,1,:],
|
||||||
|
np.cross(b_[...,0,:],b_[...,1,:]) ],axis=-2)
|
||||||
|
|
||||||
|
return Rotation.from_basis(np.swapaxes(am/np.linalg.norm(am,axis=-1,keepdims=True),-1,-2))\
|
||||||
|
.misorientation(Rotation.from_basis(np.swapaxes(bm/np.linalg.norm(bm,axis=-1,keepdims=True),-1,-2)))
|
||||||
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def from_Rodrigues(rho,
|
def from_Rodrigues(rho,
|
||||||
normalize = False,
|
normalize = False,
|
||||||
P = -1):
|
P = -1,
|
||||||
|
**kwargs):
|
||||||
"""
|
"""
|
||||||
Initialize from Rodrigues-Frank vector.
|
Initialize from Rodrigues-Frank vector.
|
||||||
|
|
||||||
|
@ -518,7 +630,7 @@ class Rotation:
|
||||||
if abs(P) != 1:
|
if abs(P) != 1:
|
||||||
raise ValueError('P ∉ {-1,1}')
|
raise ValueError('P ∉ {-1,1}')
|
||||||
|
|
||||||
if P == 1: ro[...,0:3] *= -1
|
ro[...,0:3] *= -P
|
||||||
if normalize: ro[...,0:3] /= np.linalg.norm(ro[...,0:3],axis=-1,keepdims=True)
|
if normalize: ro[...,0:3] /= np.linalg.norm(ro[...,0:3],axis=-1,keepdims=True)
|
||||||
if np.any(ro[...,3] < 0.0):
|
if np.any(ro[...,3] < 0.0):
|
||||||
raise ValueError('Rodrigues vector rotation angle not positive.')
|
raise ValueError('Rodrigues vector rotation angle not positive.')
|
||||||
|
@ -529,7 +641,8 @@ class Rotation:
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def from_homochoric(h,
|
def from_homochoric(h,
|
||||||
P = -1):
|
P = -1,
|
||||||
|
**kwargs):
|
||||||
"""
|
"""
|
||||||
Initialize from homochoric vector.
|
Initialize from homochoric vector.
|
||||||
|
|
||||||
|
@ -547,7 +660,7 @@ class Rotation:
|
||||||
if abs(P) != 1:
|
if abs(P) != 1:
|
||||||
raise ValueError('P ∉ {-1,1}')
|
raise ValueError('P ∉ {-1,1}')
|
||||||
|
|
||||||
if P == 1: ho *= -1
|
ho *= -P
|
||||||
|
|
||||||
if np.any(np.linalg.norm(ho,axis=-1) >_R1+1e-9):
|
if np.any(np.linalg.norm(ho,axis=-1) >_R1+1e-9):
|
||||||
raise ValueError('Homochoric coordinate outside of the sphere.')
|
raise ValueError('Homochoric coordinate outside of the sphere.')
|
||||||
|
@ -556,7 +669,8 @@ class Rotation:
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def from_cubochoric(c,
|
def from_cubochoric(c,
|
||||||
P = -1):
|
P = -1,
|
||||||
|
**kwargs):
|
||||||
"""
|
"""
|
||||||
Initialize from cubochoric vector.
|
Initialize from cubochoric vector.
|
||||||
|
|
||||||
|
@ -577,46 +691,15 @@ class Rotation:
|
||||||
if np.abs(np.max(cu)) > np.pi**(2./3.) * 0.5+1e-9:
|
if np.abs(np.max(cu)) > np.pi**(2./3.) * 0.5+1e-9:
|
||||||
raise ValueError('Cubochoric coordinate outside of the cube.')
|
raise ValueError('Cubochoric coordinate outside of the cube.')
|
||||||
|
|
||||||
ho = Rotation._cu2ho(cu)
|
ho = -P * Rotation._cu2ho(cu)
|
||||||
if P == 1: ho *= -1
|
|
||||||
|
|
||||||
return Rotation(Rotation._ho2qu(ho))
|
return Rotation(Rotation._ho2qu(ho))
|
||||||
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def from_average(rotations,weights = None):
|
def from_random(shape = None,
|
||||||
"""
|
seed = None,
|
||||||
Average rotation.
|
**kwargs):
|
||||||
|
|
||||||
References
|
|
||||||
----------
|
|
||||||
F. Landis Markley et al., Journal of Guidance, Control, and Dynamics 30(4):1193-1197, 2007
|
|
||||||
https://doi.org/10.2514/1.28949
|
|
||||||
|
|
||||||
Parameters
|
|
||||||
----------
|
|
||||||
rotations : list of Rotations
|
|
||||||
Rotations to average from
|
|
||||||
weights : list of floats, optional
|
|
||||||
Weights for each rotation used for averaging
|
|
||||||
|
|
||||||
"""
|
|
||||||
if not all(isinstance(item, Rotation) for item in rotations):
|
|
||||||
raise TypeError('Only instances of Rotation can be averaged.')
|
|
||||||
|
|
||||||
N = len(rotations)
|
|
||||||
if not weights:
|
|
||||||
weights = np.ones(N,dtype='i')
|
|
||||||
|
|
||||||
for i,(r,n) in enumerate(zip(rotations,weights)):
|
|
||||||
M = r.M * n if i == 0 \
|
|
||||||
else M + r.M * n # noqa add (multiples) of this rotation to average noqa
|
|
||||||
eig, vec = np.linalg.eig(M/N)
|
|
||||||
|
|
||||||
return Rotation.from_quaternion(np.real(vec.T[eig.argmax()]),accept_homomorph = True)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def from_random(shape=None,seed=None):
|
|
||||||
"""
|
"""
|
||||||
Draw random rotation.
|
Draw random rotation.
|
||||||
|
|
||||||
|
@ -633,12 +716,7 @@ class Rotation:
|
||||||
|
|
||||||
"""
|
"""
|
||||||
rng = np.random.default_rng(seed)
|
rng = np.random.default_rng(seed)
|
||||||
if shape is None:
|
r = rng.random(3 if shape is None else tuple(shape)+(3,) if hasattr(shape, '__iter__') else (shape,3))
|
||||||
r = rng.random(3)
|
|
||||||
elif hasattr(shape, '__iter__'):
|
|
||||||
r = rng.random(tuple(shape)+(3,))
|
|
||||||
else:
|
|
||||||
r = rng.random((shape,3))
|
|
||||||
|
|
||||||
A = np.sqrt(r[...,2])
|
A = np.sqrt(r[...,2])
|
||||||
B = np.sqrt(1.0-r[...,2])
|
B = np.sqrt(1.0-r[...,2])
|
||||||
|
@ -647,14 +725,17 @@ class Rotation:
|
||||||
np.cos(2.0*np.pi*r[...,1])*B,
|
np.cos(2.0*np.pi*r[...,1])*B,
|
||||||
np.sin(2.0*np.pi*r[...,0])*A],axis=-1)
|
np.sin(2.0*np.pi*r[...,0])*A],axis=-1)
|
||||||
|
|
||||||
return Rotation(q.reshape(r.shape[:-1]+(4,)) if shape is not None else q)._standardize()
|
return Rotation(q if shape is None else q.reshape(r.shape[:-1]+(4,)))._standardize()
|
||||||
|
|
||||||
# for compatibility
|
|
||||||
__mul__ = __matmul__
|
|
||||||
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def from_ODF(weights,Eulers,N=500,degrees=True,fractions=True,seed=None):
|
def from_ODF(weights,
|
||||||
|
Eulers,
|
||||||
|
N = 500,
|
||||||
|
degrees = True,
|
||||||
|
fractions = True,
|
||||||
|
seed = None,
|
||||||
|
**kwargs):
|
||||||
"""
|
"""
|
||||||
Sample discrete values from a binned ODF.
|
Sample discrete values from a binned ODF.
|
||||||
|
|
||||||
|
@ -707,7 +788,12 @@ class Rotation:
|
||||||
|
|
||||||
|
|
||||||
@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,
|
||||||
|
**kwargs):
|
||||||
"""
|
"""
|
||||||
Calculate set of rotations with Gaussian distribution around center.
|
Calculate set of rotations with Gaussian distribution around center.
|
||||||
|
|
||||||
|
@ -738,7 +824,13 @@ class Rotation:
|
||||||
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def from_fiber_component(alpha,beta,sigma=0.0,N=500,degrees=True,seed=None):
|
def from_fiber_component(alpha,
|
||||||
|
beta,
|
||||||
|
sigma = 0.0,
|
||||||
|
N = 500,
|
||||||
|
degrees = True,
|
||||||
|
seed = None,
|
||||||
|
**kwargs):
|
||||||
"""
|
"""
|
||||||
Calculate set of rotations with Gaussian distribution around direction.
|
Calculate set of rotations with Gaussian distribution around direction.
|
||||||
|
|
||||||
|
|
|
@ -175,7 +175,7 @@ class Table:
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def labels(self):
|
def labels(self):
|
||||||
return list(self.shapes.keys())
|
return list(self.shapes)
|
||||||
|
|
||||||
|
|
||||||
def get(self,label):
|
def get(self,label):
|
||||||
|
|
|
@ -0,0 +1,420 @@
|
||||||
|
import numpy as _np
|
||||||
|
|
||||||
|
kinematics = {
|
||||||
|
'cF': {
|
||||||
|
'slip' : _np.array([
|
||||||
|
[+0,+1,-1 , +1,+1,+1],
|
||||||
|
[-1,+0,+1 , +1,+1,+1],
|
||||||
|
[+1,-1,+0 , +1,+1,+1],
|
||||||
|
[+0,-1,-1 , -1,-1,+1],
|
||||||
|
[+1,+0,+1 , -1,-1,+1],
|
||||||
|
[-1,+1,+0 , -1,-1,+1],
|
||||||
|
[+0,-1,+1 , +1,-1,-1],
|
||||||
|
[-1,+0,-1 , +1,-1,-1],
|
||||||
|
[+1,+1,+0 , +1,-1,-1],
|
||||||
|
[+0,+1,+1 , -1,+1,-1],
|
||||||
|
[+1,+0,-1 , -1,+1,-1],
|
||||||
|
[-1,-1,+0 , -1,+1,-1],
|
||||||
|
[+1,+1,+0 , +1,-1,+0],
|
||||||
|
[+1,-1,+0 , +1,+1,+0],
|
||||||
|
[+1,+0,+1 , +1,+0,-1],
|
||||||
|
[+1,+0,-1 , +1,+0,+1],
|
||||||
|
[+0,+1,+1 , +0,+1,-1],
|
||||||
|
[+0,+1,-1 , +0,+1,+1],
|
||||||
|
],'d'),
|
||||||
|
'twin' : _np.array([
|
||||||
|
[-2, 1, 1, 1, 1, 1],
|
||||||
|
[ 1,-2, 1, 1, 1, 1],
|
||||||
|
[ 1, 1,-2, 1, 1, 1],
|
||||||
|
[ 2,-1, 1, -1,-1, 1],
|
||||||
|
[-1, 2, 1, -1,-1, 1],
|
||||||
|
[-1,-1,-2, -1,-1, 1],
|
||||||
|
[-2,-1,-1, 1,-1,-1],
|
||||||
|
[ 1, 2,-1, 1,-1,-1],
|
||||||
|
[ 1,-1, 2, 1,-1,-1],
|
||||||
|
[ 2, 1,-1, -1, 1,-1],
|
||||||
|
[-1,-2,-1, -1, 1,-1],
|
||||||
|
[-1, 1, 2, -1, 1,-1],
|
||||||
|
],dtype=float),
|
||||||
|
},
|
||||||
|
'cI': {
|
||||||
|
'slip' : _np.array([
|
||||||
|
[+1,-1,+1 , +0,+1,+1],
|
||||||
|
[-1,-1,+1 , +0,+1,+1],
|
||||||
|
[+1,+1,+1 , +0,-1,+1],
|
||||||
|
[-1,+1,+1 , +0,-1,+1],
|
||||||
|
[-1,+1,+1 , +1,+0,+1],
|
||||||
|
[-1,-1,+1 , +1,+0,+1],
|
||||||
|
[+1,+1,+1 , -1,+0,+1],
|
||||||
|
[+1,-1,+1 , -1,+0,+1],
|
||||||
|
[-1,+1,+1 , +1,+1,+0],
|
||||||
|
[-1,+1,-1 , +1,+1,+0],
|
||||||
|
[+1,+1,+1 , -1,+1,+0],
|
||||||
|
[+1,+1,-1 , -1,+1,+0],
|
||||||
|
[-1,+1,+1 , +2,+1,+1],
|
||||||
|
[+1,+1,+1 , -2,+1,+1],
|
||||||
|
[+1,+1,-1 , +2,-1,+1],
|
||||||
|
[+1,-1,+1 , +2,+1,-1],
|
||||||
|
[+1,-1,+1 , +1,+2,+1],
|
||||||
|
[+1,+1,-1 , -1,+2,+1],
|
||||||
|
[+1,+1,+1 , +1,-2,+1],
|
||||||
|
[-1,+1,+1 , +1,+2,-1],
|
||||||
|
[+1,+1,-1 , +1,+1,+2],
|
||||||
|
[+1,-1,+1 , -1,+1,+2],
|
||||||
|
[-1,+1,+1 , +1,-1,+2],
|
||||||
|
[+1,+1,+1 , +1,+1,-2],
|
||||||
|
],'d'),
|
||||||
|
'twin' : _np.array([
|
||||||
|
[-1, 1, 1, 2, 1, 1],
|
||||||
|
[ 1, 1, 1, -2, 1, 1],
|
||||||
|
[ 1, 1,-1, 2,-1, 1],
|
||||||
|
[ 1,-1, 1, 2, 1,-1],
|
||||||
|
[ 1,-1, 1, 1, 2, 1],
|
||||||
|
[ 1, 1,-1, -1, 2, 1],
|
||||||
|
[ 1, 1, 1, 1,-2, 1],
|
||||||
|
[-1, 1, 1, 1, 2,-1],
|
||||||
|
[ 1, 1,-1, 1, 1, 2],
|
||||||
|
[ 1,-1, 1, -1, 1, 2],
|
||||||
|
[-1, 1, 1, 1,-1, 2],
|
||||||
|
[ 1, 1, 1, 1, 1,-2],
|
||||||
|
],dtype=float),
|
||||||
|
},
|
||||||
|
'hP': {
|
||||||
|
'slip' : _np.array([
|
||||||
|
[+2,-1,-1,+0 , +0,+0,+0,+1],
|
||||||
|
[-1,+2,-1,+0 , +0,+0,+0,+1],
|
||||||
|
[-1,-1,+2,+0 , +0,+0,+0,+1],
|
||||||
|
[+2,-1,-1,+0 , +0,+1,-1,+0],
|
||||||
|
[-1,+2,-1,+0 , -1,+0,+1,+0],
|
||||||
|
[-1,-1,+2,+0 , +1,-1,+0,+0],
|
||||||
|
[-1,+1,+0,+0 , +1,+1,-2,+0],
|
||||||
|
[+0,-1,+1,+0 , -2,+1,+1,+0],
|
||||||
|
[+1,+0,-1,+0 , +1,-2,+1,+0],
|
||||||
|
[-1,+2,-1,+0 , +1,+0,-1,+1],
|
||||||
|
[-2,+1,+1,+0 , +0,+1,-1,+1],
|
||||||
|
[-1,-1,+2,+0 , -1,+1,+0,+1],
|
||||||
|
[+1,-2,+1,+0 , -1,+0,+1,+1],
|
||||||
|
[+2,-1,-1,+0 , +0,-1,+1,+1],
|
||||||
|
[+1,+1,-2,+0 , +1,-1,+0,+1],
|
||||||
|
[-2,+1,+1,+3 , +1,+0,-1,+1],
|
||||||
|
[-1,-1,+2,+3 , +1,+0,-1,+1],
|
||||||
|
[-1,-1,+2,+3 , +0,+1,-1,+1],
|
||||||
|
[+1,-2,+1,+3 , +0,+1,-1,+1],
|
||||||
|
[+1,-2,+1,+3 , -1,+1,+0,+1],
|
||||||
|
[+2,-1,-1,+3 , -1,+1,+0,+1],
|
||||||
|
[+2,-1,-1,+3 , -1,+0,+1,+1],
|
||||||
|
[+1,+1,-2,+3 , -1,+0,+1,+1],
|
||||||
|
[+1,+1,-2,+3 , +0,-1,+1,+1],
|
||||||
|
[-1,+2,-1,+3 , +0,-1,+1,+1],
|
||||||
|
[-1,+2,-1,+3 , +1,-1,+0,+1],
|
||||||
|
[-2,+1,+1,+3 , +1,-1,+0,+1],
|
||||||
|
[-1,-1,+2,+3 , +1,+1,-2,+2],
|
||||||
|
[+1,-2,+1,+3 , -1,+2,-1,+2],
|
||||||
|
[+2,-1,-1,+3 , -2,+1,+1,+2],
|
||||||
|
[+1,+1,-2,+3 , -1,-1,+2,+2],
|
||||||
|
[-1,+2,-1,+3 , +1,-2,+1,+2],
|
||||||
|
[-2,+1,+1,+3 , +2,-1,-1,+2],
|
||||||
|
],'d'),
|
||||||
|
'twin' : _np.array([
|
||||||
|
[-1, 0, 1, 1, 1, 0, -1, 2], # shear = (3-(c/a)^2)/(sqrt(3) c/a) <-10.1>{10.2}
|
||||||
|
[ 0, -1, 1, 1, 0, 1, -1, 2],
|
||||||
|
[ 1, -1, 0, 1, -1, 1, 0, 2],
|
||||||
|
[ 1, 0, -1, 1, -1, 0, 1, 2],
|
||||||
|
[ 0, 1, -1, 1, 0, -1, 1, 2],
|
||||||
|
[-1, 1, 0, 1, 1, -1, 0, 2],
|
||||||
|
[-1, -1, 2, 6, 1, 1, -2, 1], # shear = 1/(c/a) <11.6>{-1-1.1}
|
||||||
|
[ 1, -2, 1, 6, -1, 2, -1, 1],
|
||||||
|
[ 2, -1, -1, 6, -2, 1, 1, 1],
|
||||||
|
[ 1, 1, -2, 6, -1, -1, 2, 1],
|
||||||
|
[-1, 2, -1, 6, 1, -2, 1, 1],
|
||||||
|
[-2, 1, 1, 6, 2, -1, -1, 1],
|
||||||
|
[ 1, 0, -1, -2, 1, 0, -1, 1], # shear = (4(c/a)^2-9)/(4 sqrt(3) c/a) <10.-2>{10.1}
|
||||||
|
[ 0, 1, -1, -2, 0, 1, -1, 1],
|
||||||
|
[-1, 1, 0, -2, -1, 1, 0, 1],
|
||||||
|
[-1, 0, 1, -2, -1, 0, 1, 1],
|
||||||
|
[ 0, -1, 1, -2, 0, -1, 1, 1],
|
||||||
|
[ 1, -1, 0, -2, 1, -1, 0, 1],
|
||||||
|
[ 1, 1, -2, -3, 1, 1, -2, 2], # shear = 2((c/a)^2-2)/(3 c/a) <11.-3>{11.2}
|
||||||
|
[-1, 2, -1, -3, -1, 2, -1, 2],
|
||||||
|
[-2, 1, 1, -3, -2, 1, 1, 2],
|
||||||
|
[-1, -1, 2, -3, -1, -1, 2, 2],
|
||||||
|
[ 1, -2, 1, -3, 1, -2, 1, 2],
|
||||||
|
[ 2, -1, -1, -3, 2, -1, -1, 2],
|
||||||
|
],dtype=float),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
# Kurdjomov--Sachs orientation relationship for fcc <-> bcc transformation
|
||||||
|
# from S. Morito et al., Journal of Alloys and Compounds 577:s587-s592, 2013
|
||||||
|
# also see K. Kitahara et al., Acta Materialia 54:1279-1288, 2006
|
||||||
|
|
||||||
|
relations = {
|
||||||
|
'KS': {
|
||||||
|
'cF' : _np.array([
|
||||||
|
[[ -1, 0, 1],[ 1, 1, 1]],
|
||||||
|
[[ -1, 0, 1],[ 1, 1, 1]],
|
||||||
|
[[ 0, 1, -1],[ 1, 1, 1]],
|
||||||
|
[[ 0, 1, -1],[ 1, 1, 1]],
|
||||||
|
[[ 1, -1, 0],[ 1, 1, 1]],
|
||||||
|
[[ 1, -1, 0],[ 1, 1, 1]],
|
||||||
|
[[ 1, 0, -1],[ 1, -1, 1]],
|
||||||
|
[[ 1, 0, -1],[ 1, -1, 1]],
|
||||||
|
[[ -1, -1, 0],[ 1, -1, 1]],
|
||||||
|
[[ -1, -1, 0],[ 1, -1, 1]],
|
||||||
|
[[ 0, 1, 1],[ 1, -1, 1]],
|
||||||
|
[[ 0, 1, 1],[ 1, -1, 1]],
|
||||||
|
[[ 0, -1, 1],[ -1, 1, 1]],
|
||||||
|
[[ 0, -1, 1],[ -1, 1, 1]],
|
||||||
|
[[ -1, 0, -1],[ -1, 1, 1]],
|
||||||
|
[[ -1, 0, -1],[ -1, 1, 1]],
|
||||||
|
[[ 1, 1, 0],[ -1, 1, 1]],
|
||||||
|
[[ 1, 1, 0],[ -1, 1, 1]],
|
||||||
|
[[ -1, 1, 0],[ 1, 1, -1]],
|
||||||
|
[[ -1, 1, 0],[ 1, 1, -1]],
|
||||||
|
[[ 0, -1, -1],[ 1, 1, -1]],
|
||||||
|
[[ 0, -1, -1],[ 1, 1, -1]],
|
||||||
|
[[ 1, 0, 1],[ 1, 1, -1]],
|
||||||
|
[[ 1, 0, 1],[ 1, 1, -1]],
|
||||||
|
],dtype=float),
|
||||||
|
'cI' : _np.array([
|
||||||
|
[[ -1, -1, 1],[ 0, 1, 1]],
|
||||||
|
[[ -1, 1, -1],[ 0, 1, 1]],
|
||||||
|
[[ -1, -1, 1],[ 0, 1, 1]],
|
||||||
|
[[ -1, 1, -1],[ 0, 1, 1]],
|
||||||
|
[[ -1, -1, 1],[ 0, 1, 1]],
|
||||||
|
[[ -1, 1, -1],[ 0, 1, 1]],
|
||||||
|
[[ -1, -1, 1],[ 0, 1, 1]],
|
||||||
|
[[ -1, 1, -1],[ 0, 1, 1]],
|
||||||
|
[[ -1, -1, 1],[ 0, 1, 1]],
|
||||||
|
[[ -1, 1, -1],[ 0, 1, 1]],
|
||||||
|
[[ -1, -1, 1],[ 0, 1, 1]],
|
||||||
|
[[ -1, 1, -1],[ 0, 1, 1]],
|
||||||
|
[[ -1, -1, 1],[ 0, 1, 1]],
|
||||||
|
[[ -1, 1, -1],[ 0, 1, 1]],
|
||||||
|
[[ -1, -1, 1],[ 0, 1, 1]],
|
||||||
|
[[ -1, 1, -1],[ 0, 1, 1]],
|
||||||
|
[[ -1, -1, 1],[ 0, 1, 1]],
|
||||||
|
[[ -1, 1, -1],[ 0, 1, 1]],
|
||||||
|
[[ -1, -1, 1],[ 0, 1, 1]],
|
||||||
|
[[ -1, 1, -1],[ 0, 1, 1]],
|
||||||
|
[[ -1, -1, 1],[ 0, 1, 1]],
|
||||||
|
[[ -1, 1, -1],[ 0, 1, 1]],
|
||||||
|
[[ -1, -1, 1],[ 0, 1, 1]],
|
||||||
|
[[ -1, 1, -1],[ 0, 1, 1]],
|
||||||
|
],dtype=float),
|
||||||
|
},
|
||||||
|
'GT': {
|
||||||
|
'cF' : _np.array([
|
||||||
|
[[ -5,-12, 17],[ 1, 1, 1]],
|
||||||
|
[[ 17, -5,-12],[ 1, 1, 1]],
|
||||||
|
[[-12, 17, -5],[ 1, 1, 1]],
|
||||||
|
[[ 5, 12, 17],[ -1, -1, 1]],
|
||||||
|
[[-17, 5,-12],[ -1, -1, 1]],
|
||||||
|
[[ 12,-17, -5],[ -1, -1, 1]],
|
||||||
|
[[ -5, 12,-17],[ -1, 1, 1]],
|
||||||
|
[[ 17, 5, 12],[ -1, 1, 1]],
|
||||||
|
[[-12,-17, 5],[ -1, 1, 1]],
|
||||||
|
[[ 5,-12,-17],[ 1, -1, 1]],
|
||||||
|
[[-17, -5, 12],[ 1, -1, 1]],
|
||||||
|
[[ 12, 17, 5],[ 1, -1, 1]],
|
||||||
|
[[ -5, 17,-12],[ 1, 1, 1]],
|
||||||
|
[[-12, -5, 17],[ 1, 1, 1]],
|
||||||
|
[[ 17,-12, -5],[ 1, 1, 1]],
|
||||||
|
[[ 5,-17,-12],[ -1, -1, 1]],
|
||||||
|
[[ 12, 5, 17],[ -1, -1, 1]],
|
||||||
|
[[-17, 12, -5],[ -1, -1, 1]],
|
||||||
|
[[ -5,-17, 12],[ -1, 1, 1]],
|
||||||
|
[[-12, 5,-17],[ -1, 1, 1]],
|
||||||
|
[[ 17, 12, 5],[ -1, 1, 1]],
|
||||||
|
[[ 5, 17, 12],[ 1, -1, 1]],
|
||||||
|
[[ 12, -5,-17],[ 1, -1, 1]],
|
||||||
|
[[-17,-12, 5],[ 1, -1, 1]],
|
||||||
|
],dtype=float),
|
||||||
|
'cI' : _np.array([
|
||||||
|
[[-17, -7, 17],[ 1, 0, 1]],
|
||||||
|
[[ 17,-17, -7],[ 1, 1, 0]],
|
||||||
|
[[ -7, 17,-17],[ 0, 1, 1]],
|
||||||
|
[[ 17, 7, 17],[ -1, 0, 1]],
|
||||||
|
[[-17, 17, -7],[ -1, -1, 0]],
|
||||||
|
[[ 7,-17,-17],[ 0, -1, 1]],
|
||||||
|
[[-17, 7,-17],[ -1, 0, 1]],
|
||||||
|
[[ 17, 17, 7],[ -1, 1, 0]],
|
||||||
|
[[ -7,-17, 17],[ 0, 1, 1]],
|
||||||
|
[[ 17, -7,-17],[ 1, 0, 1]],
|
||||||
|
[[-17,-17, 7],[ 1, -1, 0]],
|
||||||
|
[[ 7, 17, 17],[ 0, -1, 1]],
|
||||||
|
[[-17, 17, -7],[ 1, 1, 0]],
|
||||||
|
[[ -7,-17, 17],[ 0, 1, 1]],
|
||||||
|
[[ 17, -7,-17],[ 1, 0, 1]],
|
||||||
|
[[ 17,-17, -7],[ -1, -1, 0]],
|
||||||
|
[[ 7, 17, 17],[ 0, -1, 1]],
|
||||||
|
[[-17, 7,-17],[ -1, 0, 1]],
|
||||||
|
[[-17,-17, 7],[ -1, 1, 0]],
|
||||||
|
[[ -7, 17,-17],[ 0, 1, 1]],
|
||||||
|
[[ 17, 7, 17],[ -1, 0, 1]],
|
||||||
|
[[ 17, 17, 7],[ 1, -1, 0]],
|
||||||
|
[[ 7,-17,-17],[ 0, -1, 1]],
|
||||||
|
[[-17, -7, 17],[ 1, 0, 1]],
|
||||||
|
],dtype=float),
|
||||||
|
},
|
||||||
|
'GT_prime': {
|
||||||
|
'cF' : _np.array([
|
||||||
|
[[ 0, 1, -1],[ 7, 17, 17]],
|
||||||
|
[[ -1, 0, 1],[ 17, 7, 17]],
|
||||||
|
[[ 1, -1, 0],[ 17, 17, 7]],
|
||||||
|
[[ 0, -1, -1],[ -7,-17, 17]],
|
||||||
|
[[ 1, 0, 1],[-17, -7, 17]],
|
||||||
|
[[ 1, -1, 0],[-17,-17, 7]],
|
||||||
|
[[ 0, 1, -1],[ 7,-17,-17]],
|
||||||
|
[[ 1, 0, 1],[ 17, -7,-17]],
|
||||||
|
[[ -1, -1, 0],[ 17,-17, -7]],
|
||||||
|
[[ 0, -1, -1],[ -7, 17,-17]],
|
||||||
|
[[ -1, 0, 1],[-17, 7,-17]],
|
||||||
|
[[ -1, -1, 0],[-17, 17, -7]],
|
||||||
|
[[ 0, -1, 1],[ 7, 17, 17]],
|
||||||
|
[[ 1, 0, -1],[ 17, 7, 17]],
|
||||||
|
[[ -1, 1, 0],[ 17, 17, 7]],
|
||||||
|
[[ 0, 1, 1],[ -7,-17, 17]],
|
||||||
|
[[ -1, 0, -1],[-17, -7, 17]],
|
||||||
|
[[ -1, 1, 0],[-17,-17, 7]],
|
||||||
|
[[ 0, -1, 1],[ 7,-17,-17]],
|
||||||
|
[[ -1, 0, -1],[ 17, -7,-17]],
|
||||||
|
[[ 1, 1, 0],[ 17,-17, -7]],
|
||||||
|
[[ 0, 1, 1],[ -7, 17,-17]],
|
||||||
|
[[ 1, 0, -1],[-17, 7,-17]],
|
||||||
|
[[ 1, 1, 0],[-17, 17, -7]],
|
||||||
|
],dtype=float),
|
||||||
|
'cI' : _np.array([
|
||||||
|
[[ 1, 1, -1],[ 12, 5, 17]],
|
||||||
|
[[ -1, 1, 1],[ 17, 12, 5]],
|
||||||
|
[[ 1, -1, 1],[ 5, 17, 12]],
|
||||||
|
[[ -1, -1, -1],[-12, -5, 17]],
|
||||||
|
[[ 1, -1, 1],[-17,-12, 5]],
|
||||||
|
[[ 1, -1, -1],[ -5,-17, 12]],
|
||||||
|
[[ -1, 1, -1],[ 12, -5,-17]],
|
||||||
|
[[ 1, 1, 1],[ 17,-12, -5]],
|
||||||
|
[[ -1, -1, 1],[ 5,-17,-12]],
|
||||||
|
[[ 1, -1, -1],[-12, 5,-17]],
|
||||||
|
[[ -1, -1, 1],[-17, 12, -5]],
|
||||||
|
[[ -1, -1, -1],[ -5, 17,-12]],
|
||||||
|
[[ 1, -1, 1],[ 12, 17, 5]],
|
||||||
|
[[ 1, 1, -1],[ 5, 12, 17]],
|
||||||
|
[[ -1, 1, 1],[ 17, 5, 12]],
|
||||||
|
[[ -1, 1, 1],[-12,-17, 5]],
|
||||||
|
[[ -1, -1, -1],[ -5,-12, 17]],
|
||||||
|
[[ -1, 1, -1],[-17, -5, 12]],
|
||||||
|
[[ -1, -1, 1],[ 12,-17, -5]],
|
||||||
|
[[ -1, 1, -1],[ 5,-12,-17]],
|
||||||
|
[[ 1, 1, 1],[ 17, -5,-12]],
|
||||||
|
[[ 1, 1, 1],[-12, 17, -5]],
|
||||||
|
[[ 1, -1, -1],[ -5, 12,-17]],
|
||||||
|
[[ 1, 1, -1],[-17, 5,-12]],
|
||||||
|
],dtype=float),
|
||||||
|
},
|
||||||
|
'NW': {
|
||||||
|
'cF' : _np.array([
|
||||||
|
[[ 2, -1, -1],[ 1, 1, 1]],
|
||||||
|
[[ -1, 2, -1],[ 1, 1, 1]],
|
||||||
|
[[ -1, -1, 2],[ 1, 1, 1]],
|
||||||
|
[[ -2, -1, -1],[ -1, 1, 1]],
|
||||||
|
[[ 1, 2, -1],[ -1, 1, 1]],
|
||||||
|
[[ 1, -1, 2],[ -1, 1, 1]],
|
||||||
|
[[ 2, 1, -1],[ 1, -1, 1]],
|
||||||
|
[[ -1, -2, -1],[ 1, -1, 1]],
|
||||||
|
[[ -1, 1, 2],[ 1, -1, 1]],
|
||||||
|
[[ 2, -1, 1],[ -1, -1, 1]],
|
||||||
|
[[ -1, 2, 1],[ -1, -1, 1]],
|
||||||
|
[[ -1, -1, -2],[ -1, -1, 1]],
|
||||||
|
],dtype=float),
|
||||||
|
'cI' : _np.array([
|
||||||
|
[[ 0, -1, 1],[ 0, 1, 1]],
|
||||||
|
[[ 0, -1, 1],[ 0, 1, 1]],
|
||||||
|
[[ 0, -1, 1],[ 0, 1, 1]],
|
||||||
|
[[ 0, -1, 1],[ 0, 1, 1]],
|
||||||
|
[[ 0, -1, 1],[ 0, 1, 1]],
|
||||||
|
[[ 0, -1, 1],[ 0, 1, 1]],
|
||||||
|
[[ 0, -1, 1],[ 0, 1, 1]],
|
||||||
|
[[ 0, -1, 1],[ 0, 1, 1]],
|
||||||
|
[[ 0, -1, 1],[ 0, 1, 1]],
|
||||||
|
[[ 0, -1, 1],[ 0, 1, 1]],
|
||||||
|
[[ 0, -1, 1],[ 0, 1, 1]],
|
||||||
|
[[ 0, -1, 1],[ 0, 1, 1]],
|
||||||
|
],dtype=float),
|
||||||
|
},
|
||||||
|
'Pitsch': {
|
||||||
|
'cF' : _np.array([
|
||||||
|
[[ 1, 0, 1],[ 0, 1, 0]],
|
||||||
|
[[ 1, 1, 0],[ 0, 0, 1]],
|
||||||
|
[[ 0, 1, 1],[ 1, 0, 0]],
|
||||||
|
[[ 0, 1, -1],[ 1, 0, 0]],
|
||||||
|
[[ -1, 0, 1],[ 0, 1, 0]],
|
||||||
|
[[ 1, -1, 0],[ 0, 0, 1]],
|
||||||
|
[[ 1, 0, -1],[ 0, 1, 0]],
|
||||||
|
[[ -1, 1, 0],[ 0, 0, 1]],
|
||||||
|
[[ 0, -1, 1],[ 1, 0, 0]],
|
||||||
|
[[ 0, 1, 1],[ 1, 0, 0]],
|
||||||
|
[[ 1, 0, 1],[ 0, 1, 0]],
|
||||||
|
[[ 1, 1, 0],[ 0, 0, 1]],
|
||||||
|
],dtype=float),
|
||||||
|
'cI' : _np.array([
|
||||||
|
[[ 1, -1, 1],[ -1, 0, 1]],
|
||||||
|
[[ 1, 1, -1],[ 1, -1, 0]],
|
||||||
|
[[ -1, 1, 1],[ 0, 1, -1]],
|
||||||
|
[[ -1, 1, -1],[ 0, -1, -1]],
|
||||||
|
[[ -1, -1, 1],[ -1, 0, -1]],
|
||||||
|
[[ 1, -1, -1],[ -1, -1, 0]],
|
||||||
|
[[ 1, -1, -1],[ -1, 0, -1]],
|
||||||
|
[[ -1, 1, -1],[ -1, -1, 0]],
|
||||||
|
[[ -1, -1, 1],[ 0, -1, -1]],
|
||||||
|
[[ -1, 1, 1],[ 0, -1, 1]],
|
||||||
|
[[ 1, -1, 1],[ 1, 0, -1]],
|
||||||
|
[[ 1, 1, -1],[ -1, 1, 0]],
|
||||||
|
],dtype=float),
|
||||||
|
},
|
||||||
|
'Bain': {
|
||||||
|
'cF' : _np.array([
|
||||||
|
[[ 0, 1, 0],[ 1, 0, 0]],
|
||||||
|
[[ 0, 0, 1],[ 0, 1, 0]],
|
||||||
|
[[ 1, 0, 0],[ 0, 0, 1]],
|
||||||
|
],dtype=float),
|
||||||
|
'cI' : _np.array([
|
||||||
|
[[ 0, 1, 1],[ 1, 0, 0]],
|
||||||
|
[[ 1, 0, 1],[ 0, 1, 0]],
|
||||||
|
[[ 1, 1, 0],[ 0, 0, 1]],
|
||||||
|
],dtype=float),
|
||||||
|
},
|
||||||
|
'Burgers' : {
|
||||||
|
'cI' : _np.array([
|
||||||
|
[[ -1, 1, 1],[ 1, 1, 0]],
|
||||||
|
[[ -1, 1, -1],[ 1, 1, 0]],
|
||||||
|
[[ 1, 1, 1],[ 1, -1, 0]],
|
||||||
|
[[ 1, 1, -1],[ 1, -1, 0]],
|
||||||
|
|
||||||
|
[[ 1, 1, -1],[ 1, 0, 1]],
|
||||||
|
[[ -1, 1, 1],[ 1, 0, 1]],
|
||||||
|
[[ 1, 1, 1],[ -1, 0, 1]],
|
||||||
|
[[ 1, -1, 1],[ -1, 0, 1]],
|
||||||
|
|
||||||
|
[[ -1, 1, -1],[ 0, 1, 1]],
|
||||||
|
[[ 1, 1, -1],[ 0, 1, 1]],
|
||||||
|
[[ -1, 1, 1],[ 0, -1, 1]],
|
||||||
|
[[ 1, 1, 1],[ 0, -1, 1]],
|
||||||
|
],dtype=float),
|
||||||
|
'hP' : _np.array([
|
||||||
|
[[ -1, 2, -1, 0],[ 0, 0, 0, 1]],
|
||||||
|
[[ -1, -1, 2, 0],[ 0, 0, 0, 1]],
|
||||||
|
[[ -1, 2, -1, 0],[ 0, 0, 0, 1]],
|
||||||
|
[[ -1, -1, 2, 0],[ 0, 0, 0, 1]],
|
||||||
|
|
||||||
|
[[ -1, 2, -1, 0],[ 0, 0, 0, 1]],
|
||||||
|
[[ -1, -1, 2, 0],[ 0, 0, 0, 1]],
|
||||||
|
[[ -1, 2, -1, 0],[ 0, 0, 0, 1]],
|
||||||
|
[[ -1, -1, 2, 0],[ 0, 0, 0, 1]],
|
||||||
|
|
||||||
|
[[ -1, 2, -1, 0],[ 0, 0, 0, 1]],
|
||||||
|
[[ -1, -1, 2, 0],[ 0, 0, 0, 1]],
|
||||||
|
[[ -1, 2, -1, 0],[ 0, 0, 0, 1]],
|
||||||
|
[[ -1, -1, 2, 0],[ 0, 0, 0, 1]],
|
||||||
|
],dtype=float),
|
||||||
|
},
|
||||||
|
}
|
|
@ -3,6 +3,7 @@ import datetime
|
||||||
import os
|
import os
|
||||||
import subprocess
|
import subprocess
|
||||||
import shlex
|
import shlex
|
||||||
|
import re
|
||||||
import fractions
|
import fractions
|
||||||
from functools import reduce
|
from functools import reduce
|
||||||
from optparse import Option
|
from optparse import Option
|
||||||
|
@ -20,10 +21,13 @@ __all__=[
|
||||||
'execute',
|
'execute',
|
||||||
'show_progress',
|
'show_progress',
|
||||||
'scale_to_coprime',
|
'scale_to_coprime',
|
||||||
|
'project_stereographic',
|
||||||
'hybrid_IA',
|
'hybrid_IA',
|
||||||
'return_message',
|
'return_message',
|
||||||
'extendableOption',
|
'extendableOption',
|
||||||
'execution_stamp'
|
'execution_stamp',
|
||||||
|
'shapeshifter',
|
||||||
|
'shapeblender',
|
||||||
]
|
]
|
||||||
|
|
||||||
####################################################################################################
|
####################################################################################################
|
||||||
|
@ -182,6 +186,28 @@ def scale_to_coprime(v):
|
||||||
return m
|
return m
|
||||||
|
|
||||||
|
|
||||||
|
def project_stereographic(vector,normalize=False):
|
||||||
|
"""
|
||||||
|
Apply stereographic projection to vector.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
vector : numpy.ndarray of shape (...,3)
|
||||||
|
Vector coordinates to be projected.
|
||||||
|
normalize : bool
|
||||||
|
Ensure unit length for vector. Defaults to False.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
coordinates : numpy.ndarray of shape (...,2)
|
||||||
|
Projected coordinates.
|
||||||
|
|
||||||
|
"""
|
||||||
|
v_ = vector/np.linalg.norm(vector,axis=-1,keepdims=True) if normalize else vector
|
||||||
|
return np.block([v_[...,:2]/(1+np.abs(v_[...,2:3])),
|
||||||
|
np.zeros_like(v_[...,2:3])])
|
||||||
|
|
||||||
|
|
||||||
def execution_stamp(class_name,function_name=None):
|
def execution_stamp(class_name,function_name=None):
|
||||||
"""Timestamp the execution of a (function within a) class."""
|
"""Timestamp the execution of a (function within a) class."""
|
||||||
now = datetime.datetime.now().astimezone().strftime('%Y-%m-%d %H:%M:%S%z')
|
now = datetime.datetime.now().astimezone().strftime('%Y-%m-%d %H:%M:%S%z')
|
||||||
|
@ -203,6 +229,77 @@ def hybrid_IA(dist,N,seed=None):
|
||||||
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(seed).permutation(N_inv_samples)[:N]]
|
||||||
|
|
||||||
|
|
||||||
|
def shapeshifter(fro,to,mode='left',keep_ones=False):
|
||||||
|
"""
|
||||||
|
Return a tuple that reshapes 'fro' to become broadcastable to 'to'.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
fro : tuple
|
||||||
|
Original shape of array.
|
||||||
|
to : tuple
|
||||||
|
Target shape of array after broadcasting.
|
||||||
|
len(to) cannot be less than len(fro).
|
||||||
|
mode : str, optional
|
||||||
|
Indicates whether new axes are preferably added to
|
||||||
|
either 'left' or 'right' of the original shape.
|
||||||
|
Defaults to 'left'.
|
||||||
|
keep_ones : bool, optional
|
||||||
|
Treat '1' in fro as literal value instead of dimensional placeholder.
|
||||||
|
Defaults to False.
|
||||||
|
|
||||||
|
"""
|
||||||
|
beg = dict(left ='(^.*\\b)',
|
||||||
|
right='(^.*?\\b)')
|
||||||
|
sep = dict(left ='(.*\\b)',
|
||||||
|
right='(.*?\\b)')
|
||||||
|
end = dict(left ='(.*?$)',
|
||||||
|
right='(.*$)')
|
||||||
|
fro = (1,) if not len(fro) else fro
|
||||||
|
to = (1,) if not len(to) else to
|
||||||
|
try:
|
||||||
|
grp = re.match(beg[mode]
|
||||||
|
+f',{sep[mode]}'.join(map(lambda x: f'{x}'
|
||||||
|
if x>1 or (keep_ones and len(fro)>1) else
|
||||||
|
'\\d+',fro))
|
||||||
|
+f',{end[mode]}',
|
||||||
|
','.join(map(str,to))+',').groups()
|
||||||
|
except AttributeError:
|
||||||
|
raise ValueError(f'Shapes can not be shifted {fro} --> {to}')
|
||||||
|
fill = ()
|
||||||
|
for g,d in zip(grp,fro+(None,)):
|
||||||
|
fill += (1,)*g.count(',')+(d,)
|
||||||
|
return fill[:-1]
|
||||||
|
|
||||||
|
|
||||||
|
def shapeblender(a,b):
|
||||||
|
"""
|
||||||
|
Return a shape that overlaps the rightmost entries of 'a' with the leftmost of 'b'.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
a : tuple
|
||||||
|
Shape of first array.
|
||||||
|
b : tuple
|
||||||
|
Shape of second array.
|
||||||
|
|
||||||
|
Examples
|
||||||
|
--------
|
||||||
|
>>> shapeblender((4,4,3),(3,2,1))
|
||||||
|
(4,4,3,2,1)
|
||||||
|
>>> shapeblender((1,2),(1,2,3))
|
||||||
|
(1,2,3)
|
||||||
|
>>> shapeblender((1,),(2,2,1))
|
||||||
|
(1,2,2,1)
|
||||||
|
>>> shapeblender((3,2),(3,2))
|
||||||
|
(3,2)
|
||||||
|
|
||||||
|
"""
|
||||||
|
i = min(len(a),len(b))
|
||||||
|
while i > 0 and a[-i:] != b[:i]: i -= 1
|
||||||
|
return a + b[i:]
|
||||||
|
|
||||||
|
|
||||||
####################################################################################################
|
####################################################################################################
|
||||||
# Classes
|
# Classes
|
||||||
####################################################################################################
|
####################################################################################################
|
||||||
|
|
|
@ -33,12 +33,12 @@ material:
|
||||||
|
|
||||||
phase:
|
phase:
|
||||||
Aluminum:
|
Aluminum:
|
||||||
lattice: fcc
|
lattice: cF
|
||||||
mech:
|
mech:
|
||||||
output: [F, P, F_e, F_p, L_p]
|
output: [F, P, F_e, F_p, L_p]
|
||||||
elasticity: {C_11: 106.75e9, C_12: 60.41e9, C_44: 28.34e9, type: hooke}
|
elasticity: {C_11: 106.75e9, C_12: 60.41e9, C_44: 28.34e9, type: hooke}
|
||||||
Steel:
|
Steel:
|
||||||
lattice: bcc
|
lattice: cI
|
||||||
mech:
|
mech:
|
||||||
output: [F, P, F_e, F_p, L_p]
|
output: [F, P, F_e, F_p, L_p]
|
||||||
elasticity: {C_11: 233.3e9, C_12: 135.5e9, C_44: 118.0e9, type: hooke}
|
elasticity: {C_11: 233.3e9, C_12: 135.5e9, C_44: 118.0e9, type: hooke}
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
1 header
|
||||||
|
1_Eulers 2_Eulers 3_Eulers 1_pos 2_pos
|
||||||
|
180.0 45.00000000000001 180.0 1 1
|
||||||
|
270.0 45.00000000000001 90.0 1 2
|
||||||
|
315.0 0.0 0.0 1 3
|
|
@ -0,0 +1,26 @@
|
||||||
|
1 header
|
||||||
|
1_Eulers 2_Eulers 3_Eulers 1_pos 2_pos
|
||||||
|
146.75362934444064 9.976439066337804 256.395594327347 1 1
|
||||||
|
356.59977719102034 43.39784965440254 12.173896584899929 1 2
|
||||||
|
75.92521636876346 43.82007387041961 277.8843642946069 1 3
|
||||||
|
326.75362934444064 9.976439066337806 76.39559432734703 1 4
|
||||||
|
176.59977719102034 43.397849654402556 192.17389658489986 1 5
|
||||||
|
255.92521636876344 43.82007387041961 97.88436429460687 1 6
|
||||||
|
213.24637065555936 9.976439066337804 103.604405672653 1 7
|
||||||
|
3.400222808979685 43.39784965440255 347.8261034151001 1 8
|
||||||
|
284.0747836312365 43.82007387041961 82.11563570539313 1 9
|
||||||
|
33.24637065555936 9.976439066337804 283.60440567265294 1 10
|
||||||
|
183.40022280897963 43.397849654402556 167.8261034151001 1 11
|
||||||
|
104.07478363123654 43.82007387041961 262.1156357053931 1 12
|
||||||
|
273.4002228089796 43.397849654402556 77.82610341510008 1 13
|
||||||
|
123.24637065555939 9.976439066337806 193.60440567265297 1 14
|
||||||
|
194.07478363123653 43.82007387041961 172.11563570539317 1 15
|
||||||
|
93.40022280897969 43.39784965440255 257.8261034151001 1 16
|
||||||
|
303.24637065555936 9.976439066337804 13.604405672652977 1 17
|
||||||
|
14.074783631236542 43.82007387041961 352.1156357053931 1 18
|
||||||
|
86.59977719102032 43.39784965440254 282.17389658489986 1 19
|
||||||
|
236.75362934444058 9.976439066337804 166.39559432734703 1 20
|
||||||
|
165.92521636876344 43.82007387041961 187.88436429460683 1 21
|
||||||
|
266.59977719102034 43.39784965440254 102.17389658489992 1 22
|
||||||
|
56.75362934444064 9.976439066337804 346.395594327347 1 23
|
||||||
|
345.9252163687635 43.82007387041961 7.884364294606862 1 24
|
|
@ -0,0 +1,26 @@
|
||||||
|
1 header
|
||||||
|
1_Eulers 2_Eulers 3_Eulers 1_pos 2_pos
|
||||||
|
166.39559432734697 9.976439066337804 236.75362934444058 1 1
|
||||||
|
352.1156357053931 43.82007387041961 14.074783631236542 1 2
|
||||||
|
77.82610341510008 43.397849654402556 273.4002228089796 1 3
|
||||||
|
346.395594327347 9.976439066337804 56.75362934444064 1 4
|
||||||
|
172.11563570539317 43.82007387041961 194.07478363123653 1 5
|
||||||
|
257.8261034151001 43.39784965440255 93.40022280897969 1 6
|
||||||
|
193.604405672653 9.976439066337804 123.24637065555939 1 7
|
||||||
|
7.884364294606862 43.82007387041961 345.9252163687635 1 8
|
||||||
|
282.17389658489986 43.39784965440254 86.59977719102032 1 9
|
||||||
|
13.604405672652977 9.976439066337804 303.24637065555936 1 10
|
||||||
|
187.88436429460683 43.82007387041961 165.92521636876344 1 11
|
||||||
|
102.17389658489992 43.39784965440254 266.59977719102034 1 12
|
||||||
|
277.8843642946069 43.82007387041961 75.92521636876346 1 13
|
||||||
|
103.604405672653 9.976439066337804 213.24637065555936 1 14
|
||||||
|
192.17389658489986 43.397849654402556 176.59977719102034 1 15
|
||||||
|
97.88436429460687 43.82007387041961 255.92521636876344 1 16
|
||||||
|
283.60440567265294 9.976439066337804 33.24637065555936 1 17
|
||||||
|
12.173896584899929 43.39784965440254 356.59977719102034 1 18
|
||||||
|
82.11563570539313 43.82007387041961 284.0747836312365 1 19
|
||||||
|
256.395594327347 9.976439066337804 146.75362934444064 1 20
|
||||||
|
167.8261034151001 43.397849654402556 183.40022280897963 1 21
|
||||||
|
262.1156357053931 43.82007387041961 104.07478363123654 1 22
|
||||||
|
76.39559432734703 9.976439066337806 326.75362934444064 1 23
|
||||||
|
347.8261034151001 43.39784965440255 3.400222808979685 1 24
|
|
@ -0,0 +1,26 @@
|
||||||
|
1 header
|
||||||
|
1_Eulers 2_Eulers 3_Eulers 1_pos 2_pos
|
||||||
|
114.20342833932975 10.52877936550932 204.20342833932972 1 1
|
||||||
|
94.3573968784815 80.40593177313954 311.22729452432543 1 2
|
||||||
|
175.6426031215185 80.40593177313954 48.77270547567447 1 3
|
||||||
|
155.79657166067025 10.52877936550932 155.79657166067025 1 4
|
||||||
|
99.62136089109411 85.70366403943004 318.04510841542015 1 5
|
||||||
|
170.37863910890587 85.70366403943002 41.954891584579855 1 6
|
||||||
|
85.64260312151852 80.40593177313954 48.77270547567448 1 7
|
||||||
|
65.79657166067024 10.52877936550932 155.79657166067025 1 8
|
||||||
|
9.621360891094124 85.70366403943004 318.04510841542015 1 9
|
||||||
|
80.37863910890587 85.70366403943004 41.95489158457987 1 10
|
||||||
|
24.203428339329758 10.52877936550932 204.20342833932975 1 11
|
||||||
|
4.357396878481486 80.40593177313954 311.2272945243255 1 12
|
||||||
|
204.20342833932972 10.52877936550932 204.20342833932972 1 13
|
||||||
|
184.35739687848147 80.40593177313954 311.2272945243255 1 14
|
||||||
|
265.64260312151845 80.40593177313953 48.77270547567449 1 15
|
||||||
|
245.79657166067025 10.528779365509317 155.79657166067025 1 16
|
||||||
|
189.62136089109413 85.70366403943004 318.04510841542015 1 17
|
||||||
|
260.3786391089059 85.70366403943002 41.954891584579855 1 18
|
||||||
|
170.37863910890587 94.29633596056996 138.04510841542015 1 19
|
||||||
|
99.62136089109411 94.29633596056998 221.95489158457983 1 20
|
||||||
|
155.79657166067025 169.4712206344907 24.203428339329754 1 21
|
||||||
|
175.64260312151848 99.59406822686046 131.22729452432552 1 22
|
||||||
|
94.35739687848151 99.59406822686046 228.77270547567446 1 23
|
||||||
|
114.20342833932975 169.4712206344907 335.7965716606702 1 24
|
|
@ -0,0 +1,14 @@
|
||||||
|
1 header
|
||||||
|
1_Eulers 2_Eulers 3_Eulers 1_pos 2_pos
|
||||||
|
96.91733794010702 83.13253115922213 314.5844440567886 1 1
|
||||||
|
173.082662059893 83.13253115922211 45.41555594321143 1 2
|
||||||
|
135.0 9.735610317245317 180.0 1 3
|
||||||
|
263.082662059893 83.13253115922213 45.415555943211444 1 4
|
||||||
|
186.91733794010702 83.13253115922211 314.5844440567886 1 5
|
||||||
|
224.99999999999997 9.735610317245317 180.0 1 6
|
||||||
|
83.082662059893 83.13253115922213 45.415555943211444 1 7
|
||||||
|
6.917337940106983 83.13253115922211 314.5844440567886 1 8
|
||||||
|
45.0 9.73561031724532 180.0 1 9
|
||||||
|
13.638707279476469 45.81931182053557 80.40196970123216 1 10
|
||||||
|
256.36129272052347 45.81931182053556 279.59803029876775 1 11
|
||||||
|
315.0 99.73561031724536 0.0 1 12
|
|
@ -0,0 +1,14 @@
|
||||||
|
1 header
|
||||||
|
1_Eulers 2_Eulers 3_Eulers 1_pos 2_pos
|
||||||
|
135.41555594321144 83.13253115922213 173.082662059893 1 1
|
||||||
|
260.26438968275465 90.0 135.0 1 2
|
||||||
|
260.40196970123213 45.81931182053557 13.638707279476478 1 3
|
||||||
|
314.5844440567886 83.13253115922213 96.91733794010702 1 4
|
||||||
|
350.40196970123213 45.81931182053557 283.6387072794765 1 5
|
||||||
|
170.26438968275465 90.0 224.99999999999997 1 6
|
||||||
|
315.4155559432114 83.13253115922213 353.08266205989304 1 7
|
||||||
|
99.73561031724536 90.0 225.0 1 8
|
||||||
|
279.59803029876787 45.819311820535574 166.36129272052352 1 9
|
||||||
|
134.58444405678856 83.13253115922213 276.91733794010696 1 10
|
||||||
|
9.598030298767851 45.819311820535574 76.36129272052355 1 11
|
||||||
|
9.735610317245369 90.0 315.0 1 12
|
|
@ -0,0 +1,19 @@
|
||||||
|
3x3:1_Schmid 3x3:2_Schmid 3x3:3_Schmid 3x3:4_Schmid 3x3:5_Schmid 3x3:6_Schmid 3x3:7_Schmid 3x3:8_Schmid 3x3:9_Schmid
|
||||||
|
0.0 0.0 0.0 0.408248290463863 0.408248290463863 0.40824829046386296 -0.4082482904638631 -0.4082482904638631 -0.408248290463863
|
||||||
|
-0.408248290463863 -0.408248290463863 -0.40824829046386296 2.4997998108697446e-17 2.4997998108697446e-17 2.499799810869744e-17 0.4082482904638631 0.4082482904638631 0.408248290463863
|
||||||
|
0.408248290463863 0.408248290463863 0.40824829046386296 -0.4082482904638631 -0.4082482904638631 -0.408248290463863 0.0 0.0 0.0
|
||||||
|
4.999599621739488e-17 4.9995996217394874e-17 -4.999599621739488e-17 0.408248290463863 0.40824829046386296 -0.408248290463863 0.408248290463863 0.40824829046386296 -0.408248290463863
|
||||||
|
-0.408248290463863 -0.40824829046386296 0.408248290463863 -2.499799810869744e-17 -2.4997998108697437e-17 2.499799810869744e-17 -0.408248290463863 -0.40824829046386296 0.408248290463863
|
||||||
|
0.408248290463863 0.40824829046386296 -0.408248290463863 -0.4082482904638631 -0.408248290463863 0.4082482904638631 0.0 0.0 0.0
|
||||||
|
0.0 0.0 0.0 -0.408248290463863 0.408248290463863 0.408248290463863 0.4082482904638631 -0.4082482904638631 -0.4082482904638631
|
||||||
|
-0.408248290463863 0.408248290463863 0.408248290463863 -2.499799810869744e-17 2.499799810869744e-17 2.499799810869744e-17 -0.408248290463863 0.408248290463863 0.408248290463863
|
||||||
|
0.408248290463863 -0.408248290463863 -0.408248290463863 0.408248290463863 -0.408248290463863 -0.408248290463863 0.0 0.0 0.0
|
||||||
|
-4.999599621739488e-17 4.999599621739488e-17 -4.9995996217394874e-17 -0.408248290463863 0.408248290463863 -0.40824829046386296 -0.408248290463863 0.408248290463863 -0.40824829046386296
|
||||||
|
-0.408248290463863 0.408248290463863 -0.40824829046386296 2.4997998108697446e-17 -2.4997998108697446e-17 2.499799810869744e-17 0.4082482904638631 -0.4082482904638631 0.408248290463863
|
||||||
|
0.408248290463863 -0.408248290463863 0.40824829046386296 0.408248290463863 -0.408248290463863 0.40824829046386296 0.0 0.0 0.0
|
||||||
|
0.4999999999999999 -0.4999999999999999 0.0 0.4999999999999999 -0.4999999999999999 0.0 0.0 0.0 0.0
|
||||||
|
0.5 0.4999999999999999 -6.123233995736766e-17 -0.5000000000000001 -0.5 6.123233995736767e-17 0.0 0.0 0.0
|
||||||
|
0.4999999999999999 -3.0616169978683824e-17 -0.4999999999999999 3.0616169978683824e-17 -1.874699728327322e-33 -3.0616169978683824e-17 0.4999999999999999 -3.0616169978683824e-17 -0.4999999999999999
|
||||||
|
0.5 -3.061616997868383e-17 0.4999999999999999 -3.0616169978683836e-17 1.8746997283273227e-33 -3.061616997868383e-17 -0.5000000000000001 3.0616169978683836e-17 -0.5
|
||||||
|
0.0 6.123233995736765e-17 -6.123233995736765e-17 0.0 0.4999999999999999 -0.4999999999999999 0.0 0.4999999999999999 -0.4999999999999999
|
||||||
|
0.0 0.0 0.0 0.0 0.5 0.4999999999999999 0.0 -0.5000000000000001 -0.5
|
|
@ -0,0 +1,13 @@
|
||||||
|
3x3:1_Schmid 3x3:2_Schmid 3x3:3_Schmid 3x3:4_Schmid 3x3:5_Schmid 3x3:6_Schmid 3x3:7_Schmid 3x3:8_Schmid 3x3:9_Schmid
|
||||||
|
-0.4714045207910318 -0.4714045207910318 -0.47140452079103173 0.2357022603955159 0.2357022603955159 0.23570226039551587 0.2357022603955159 0.2357022603955159 0.23570226039551587
|
||||||
|
0.2357022603955159 0.2357022603955159 0.23570226039551587 -0.4714045207910318 -0.4714045207910318 -0.47140452079103173 0.2357022603955159 0.2357022603955159 0.23570226039551587
|
||||||
|
0.23570226039551587 0.23570226039551587 0.23570226039551584 0.23570226039551587 0.23570226039551587 0.23570226039551584 -0.4714045207910318 -0.4714045207910318 -0.47140452079103173
|
||||||
|
-0.4714045207910318 -0.47140452079103173 0.4714045207910318 0.23570226039551587 0.23570226039551584 -0.23570226039551587 -0.2357022603955159 -0.23570226039551587 0.2357022603955159
|
||||||
|
0.23570226039551584 0.23570226039551578 -0.23570226039551584 -0.4714045207910318 -0.47140452079103173 0.4714045207910318 -0.2357022603955159 -0.23570226039551587 0.2357022603955159
|
||||||
|
0.2357022603955159 0.23570226039551587 -0.2357022603955159 0.2357022603955159 0.23570226039551587 -0.2357022603955159 0.4714045207910317 0.47140452079103157 -0.4714045207910317
|
||||||
|
-0.4714045207910318 0.4714045207910318 0.4714045207910318 -0.2357022603955159 0.2357022603955159 0.2357022603955159 -0.2357022603955159 0.2357022603955159 0.2357022603955159
|
||||||
|
0.23570226039551595 -0.23570226039551595 -0.23570226039551595 0.4714045207910318 -0.4714045207910318 -0.4714045207910318 -0.2357022603955159 0.2357022603955159 0.2357022603955159
|
||||||
|
0.2357022603955159 -0.2357022603955159 -0.2357022603955159 -0.23570226039551587 0.23570226039551587 0.23570226039551587 0.4714045207910318 -0.4714045207910318 -0.4714045207910318
|
||||||
|
-0.4714045207910318 0.4714045207910318 -0.47140452079103173 -0.23570226039551587 0.23570226039551587 -0.23570226039551584 0.2357022603955159 -0.2357022603955159 0.23570226039551587
|
||||||
|
0.23570226039551595 -0.23570226039551595 0.2357022603955159 0.4714045207910318 -0.4714045207910318 0.47140452079103173 0.2357022603955159 -0.2357022603955159 0.23570226039551587
|
||||||
|
0.23570226039551584 -0.23570226039551584 0.23570226039551578 -0.23570226039551595 0.23570226039551595 -0.2357022603955159 -0.4714045207910318 0.4714045207910318 -0.47140452079103173
|
|
@ -0,0 +1,5 @@
|
||||||
|
1 header
|
||||||
|
1_Eulers 2_Eulers 3_Eulers 1_pos 2_pos
|
||||||
|
0.0 45.00000000000001 0.0 1 1
|
||||||
|
90.0 45.00000000000001 270.0 1 2
|
||||||
|
45.00000000000001 0.0 0.0 1 3
|
|
@ -0,0 +1,26 @@
|
||||||
|
1 header
|
||||||
|
1_Eulers 2_Eulers 3_Eulers 1_pos 2_pos
|
||||||
|
283.60440567265294 9.976439066337804 33.24637065555936 1 1
|
||||||
|
167.8261034151001 43.397849654402556 183.40022280897963 1 2
|
||||||
|
262.1156357053931 43.82007387041961 104.07478363123654 1 3
|
||||||
|
103.604405672653 9.976439066337804 213.24637065555936 1 4
|
||||||
|
347.8261034151001 43.39784965440255 3.400222808979685 1 5
|
||||||
|
82.11563570539313 43.82007387041961 284.0747836312365 1 6
|
||||||
|
76.39559432734703 9.976439066337806 326.75362934444064 1 7
|
||||||
|
192.17389658489986 43.397849654402556 176.59977719102034 1 8
|
||||||
|
97.88436429460687 43.82007387041961 255.92521636876344 1 9
|
||||||
|
256.395594327347 9.976439066337804 146.75362934444064 1 10
|
||||||
|
12.173896584899929 43.39784965440254 356.59977719102034 1 11
|
||||||
|
277.8843642946069 43.82007387041961 75.92521636876346 1 12
|
||||||
|
102.17389658489992 43.39784965440254 266.59977719102034 1 13
|
||||||
|
346.395594327347 9.976439066337804 56.75362934444064 1 14
|
||||||
|
7.884364294606862 43.82007387041961 345.9252163687635 1 15
|
||||||
|
282.17389658489986 43.39784965440254 86.59977719102032 1 16
|
||||||
|
166.39559432734703 9.976439066337804 236.75362934444058 1 17
|
||||||
|
187.88436429460683 43.82007387041961 165.92521636876344 1 18
|
||||||
|
257.8261034151001 43.39784965440255 93.40022280897969 1 19
|
||||||
|
13.604405672652977 9.976439066337804 303.24637065555936 1 20
|
||||||
|
352.1156357053931 43.82007387041961 14.074783631236542 1 21
|
||||||
|
77.82610341510008 43.397849654402556 273.4002228089796 1 22
|
||||||
|
193.60440567265297 9.976439066337806 123.24637065555939 1 23
|
||||||
|
172.11563570539317 43.82007387041961 194.07478363123653 1 24
|
|
@ -0,0 +1,26 @@
|
||||||
|
1 header
|
||||||
|
1_Eulers 2_Eulers 3_Eulers 1_pos 2_pos
|
||||||
|
303.24637065555936 9.976439066337804 13.604405672652977 1 1
|
||||||
|
165.92521636876344 43.82007387041961 187.88436429460683 1 2
|
||||||
|
266.59977719102034 43.39784965440254 102.17389658489992 1 3
|
||||||
|
123.24637065555939 9.976439066337804 193.604405672653 1 4
|
||||||
|
345.9252163687635 43.82007387041961 7.884364294606862 1 5
|
||||||
|
86.59977719102032 43.39784965440254 282.17389658489986 1 6
|
||||||
|
56.75362934444064 9.976439066337804 346.395594327347 1 7
|
||||||
|
194.07478363123653 43.82007387041961 172.11563570539317 1 8
|
||||||
|
93.40022280897969 43.39784965440255 257.8261034151001 1 9
|
||||||
|
236.75362934444058 9.976439066337804 166.39559432734697 1 10
|
||||||
|
14.074783631236542 43.82007387041961 352.1156357053931 1 11
|
||||||
|
273.4002228089796 43.397849654402556 77.82610341510008 1 12
|
||||||
|
104.07478363123654 43.82007387041961 262.1156357053931 1 13
|
||||||
|
326.75362934444064 9.976439066337806 76.39559432734703 1 14
|
||||||
|
3.400222808979685 43.39784965440255 347.8261034151001 1 15
|
||||||
|
284.0747836312365 43.82007387041961 82.11563570539313 1 16
|
||||||
|
146.75362934444064 9.976439066337804 256.395594327347 1 17
|
||||||
|
183.40022280897963 43.397849654402556 167.8261034151001 1 18
|
||||||
|
255.92521636876344 43.82007387041961 97.88436429460687 1 19
|
||||||
|
33.24637065555936 9.976439066337804 283.60440567265294 1 20
|
||||||
|
356.59977719102034 43.39784965440254 12.173896584899929 1 21
|
||||||
|
75.92521636876346 43.82007387041961 277.8843642946069 1 22
|
||||||
|
213.24637065555936 9.976439066337804 103.604405672653 1 23
|
||||||
|
176.59977719102034 43.397849654402556 192.17389658489986 1 24
|
|
@ -0,0 +1,26 @@
|
||||||
|
1 header
|
||||||
|
1_Eulers 2_Eulers 3_Eulers 1_pos 2_pos
|
||||||
|
335.7965716606702 10.528779365509317 65.79657166067024 1 1
|
||||||
|
228.77270547567446 80.40593177313953 85.64260312151849 1 2
|
||||||
|
131.22729452432552 80.40593177313954 4.357396878481506 1 3
|
||||||
|
24.20342833932977 10.52877936550932 24.20342833932976 1 4
|
||||||
|
221.95489158457983 85.70366403943002 80.37863910890589 1 5
|
||||||
|
138.04510841542015 85.70366403943004 9.621360891094124 1 6
|
||||||
|
131.22729452432552 80.40593177313953 94.35739687848151 1 7
|
||||||
|
24.203428339329765 10.52877936550932 114.20342833932976 1 8
|
||||||
|
221.95489158457983 85.70366403943004 170.37863910890587 1 9
|
||||||
|
138.04510841542015 85.70366403943004 99.62136089109411 1 10
|
||||||
|
335.7965716606702 10.52877936550932 155.79657166067025 1 11
|
||||||
|
228.77270547567448 80.40593177313954 175.6426031215185 1 12
|
||||||
|
335.7965716606702 10.52877936550932 335.7965716606702 1 13
|
||||||
|
228.77270547567448 80.40593177313954 355.6426031215185 1 14
|
||||||
|
131.2272945243255 80.40593177313954 274.35739687848144 1 15
|
||||||
|
24.203428339329747 10.52877936550932 294.2034283393298 1 16
|
||||||
|
221.95489158457985 85.70366403943004 350.3786391089059 1 17
|
||||||
|
138.04510841542015 85.70366403943004 279.6213608910941 1 18
|
||||||
|
41.95489158457986 94.29633596056998 9.621360891094133 1 19
|
||||||
|
318.04510841542015 94.29633596056996 80.37863910890589 1 20
|
||||||
|
155.79657166067025 169.4712206344907 24.203428339329754 1 21
|
||||||
|
48.77270547567448 99.59406822686046 4.357396878481504 1 22
|
||||||
|
311.2272945243255 99.59406822686046 85.64260312151852 1 23
|
||||||
|
204.20342833932975 169.4712206344907 65.79657166067024 1 24
|
|
@ -0,0 +1,14 @@
|
||||||
|
1 header
|
||||||
|
1_Eulers 2_Eulers 3_Eulers 1_pos 2_pos
|
||||||
|
225.41555594321144 83.13253115922213 83.08266205989301 1 1
|
||||||
|
134.58444405678856 83.13253115922211 6.917337940107012 1 2
|
||||||
|
4.702125169424418e-15 9.735610317245317 45.0 1 3
|
||||||
|
134.58444405678856 83.13253115922213 276.91733794010696 1 4
|
||||||
|
225.4155559432114 83.13253115922213 353.082662059893 1 5
|
||||||
|
0.0 9.735610317245317 315.0 1 6
|
||||||
|
134.58444405678858 83.13253115922213 96.91733794010702 1 7
|
||||||
|
225.41555594321142 83.13253115922213 173.082662059893 1 8
|
||||||
|
0.0 9.735610317245317 135.0 1 9
|
||||||
|
99.59803029876785 45.81931182053557 166.36129272052355 1 10
|
||||||
|
260.40196970123213 45.81931182053556 283.6387072794765 1 11
|
||||||
|
180.0 99.73561031724535 225.0 1 12
|
|
@ -0,0 +1,14 @@
|
||||||
|
1 header
|
||||||
|
1_Eulers 2_Eulers 3_Eulers 1_pos 2_pos
|
||||||
|
6.9173379401070045 83.13253115922213 44.58444405678856 1 1
|
||||||
|
45.0 89.99999999999999 279.7356103172453 1 2
|
||||||
|
166.36129272052352 45.819311820535574 279.59803029876787 1 3
|
||||||
|
83.08266205989301 83.13253115922213 225.41555594321144 1 4
|
||||||
|
256.3612927205235 45.819311820535574 189.59803029876787 1 5
|
||||||
|
315.0 90.0 9.735610317245369 1 6
|
||||||
|
186.917337940107 83.13253115922213 224.58444405678856 1 7
|
||||||
|
315.0 90.0 80.26438968275463 1 8
|
||||||
|
13.638707279476478 45.81931182053557 260.40196970123213 1 9
|
||||||
|
263.082662059893 83.13253115922213 45.415555943211444 1 10
|
||||||
|
103.63870727947646 45.819311820535574 170.40196970123213 1 11
|
||||||
|
224.99999999999997 90.0 170.26438968275465 1 12
|
|
@ -0,0 +1,25 @@
|
||||||
|
3x3:1_Schmid 3x3:2_Schmid 3x3:3_Schmid 3x3:4_Schmid 3x3:5_Schmid 3x3:6_Schmid 3x3:7_Schmid 3x3:8_Schmid 3x3:9_Schmid
|
||||||
|
0.0 0.4082482904638631 0.408248290463863 0.0 -0.408248290463863 -0.40824829046386296 0.0 0.4082482904638631 0.408248290463863
|
||||||
|
0.0 -0.408248290463863 -0.40824829046386296 0.0 -0.408248290463863 -0.40824829046386296 0.0 0.4082482904638631 0.408248290463863
|
||||||
|
0.0 -0.408248290463863 0.408248290463863 0.0 -0.408248290463863 0.408248290463863 0.0 -0.408248290463863 0.408248290463863
|
||||||
|
0.0 0.40824829046386285 -0.40824829046386285 0.0 -0.408248290463863 0.408248290463863 0.0 -0.408248290463863 0.408248290463863
|
||||||
|
-0.40824829046386296 2.4997998108697434e-17 -0.40824829046386285 0.4082482904638631 -2.4997998108697446e-17 0.408248290463863 0.4082482904638631 -2.4997998108697446e-17 0.408248290463863
|
||||||
|
-0.408248290463863 2.499799810869744e-17 -0.40824829046386296 -0.408248290463863 2.499799810869744e-17 -0.40824829046386296 0.4082482904638631 -2.4997998108697446e-17 0.408248290463863
|
||||||
|
-0.408248290463863 2.499799810869744e-17 0.408248290463863 -0.408248290463863 2.499799810869744e-17 0.408248290463863 -0.408248290463863 2.499799810869744e-17 0.408248290463863
|
||||||
|
-0.408248290463863 2.499799810869744e-17 0.408248290463863 0.40824829046386296 -2.4997998108697437e-17 -0.40824829046386296 -0.408248290463863 2.499799810869744e-17 0.408248290463863
|
||||||
|
-0.40824829046386296 -0.40824829046386285 4.999599621739487e-17 0.4082482904638631 0.408248290463863 -4.999599621739489e-17 0.4082482904638631 0.408248290463863 -4.999599621739489e-17
|
||||||
|
-0.4082482904638631 -0.408248290463863 4.999599621739489e-17 0.408248290463863 0.40824829046386296 -4.999599621739488e-17 -0.4082482904638631 -0.408248290463863 4.999599621739489e-17
|
||||||
|
-0.408248290463863 0.408248290463863 0.0 -0.408248290463863 0.408248290463863 0.0 -0.408248290463863 0.408248290463863 0.0
|
||||||
|
-0.40824829046386296 0.40824829046386296 0.0 -0.40824829046386296 0.40824829046386296 0.0 0.408248290463863 -0.408248290463863 0.0
|
||||||
|
-0.4714045207910316 -0.23570226039551578 -0.23570226039551576 0.4714045207910318 0.23570226039551587 0.23570226039551584 0.4714045207910318 0.23570226039551587 0.23570226039551584
|
||||||
|
-0.4714045207910318 0.23570226039551595 0.2357022603955159 -0.4714045207910318 0.23570226039551595 0.2357022603955159 -0.4714045207910318 0.23570226039551595 0.2357022603955159
|
||||||
|
0.47140452079103173 -0.2357022603955159 0.23570226039551584 0.47140452079103173 -0.2357022603955159 0.23570226039551584 -0.4714045207910318 0.23570226039551595 -0.23570226039551587
|
||||||
|
0.4714045207910318 0.23570226039551587 -0.23570226039551595 -0.47140452079103173 -0.23570226039551584 0.2357022603955159 0.4714045207910318 0.23570226039551587 -0.23570226039551595
|
||||||
|
0.2357022603955159 0.4714045207910318 0.23570226039551584 -0.23570226039551587 -0.47140452079103173 -0.23570226039551578 0.2357022603955159 0.4714045207910318 0.23570226039551584
|
||||||
|
-0.23570226039551587 0.47140452079103173 0.23570226039551587 -0.23570226039551587 0.47140452079103173 0.23570226039551587 0.2357022603955159 -0.4714045207910318 -0.2357022603955159
|
||||||
|
0.2357022603955159 -0.4714045207910318 0.23570226039551595 0.2357022603955159 -0.4714045207910318 0.23570226039551595 0.2357022603955159 -0.4714045207910318 0.23570226039551595
|
||||||
|
-0.2357022603955158 -0.4714045207910316 0.23570226039551584 0.2357022603955159 0.4714045207910318 -0.23570226039551595 0.2357022603955159 0.4714045207910318 -0.23570226039551595
|
||||||
|
0.23570226039551587 0.23570226039551584 0.47140452079103173 0.23570226039551587 0.23570226039551584 0.47140452079103173 -0.2357022603955159 -0.23570226039551587 -0.4714045207910318
|
||||||
|
-0.2357022603955159 0.2357022603955159 0.4714045207910318 0.23570226039551587 -0.23570226039551587 -0.47140452079103173 -0.2357022603955159 0.2357022603955159 0.4714045207910318
|
||||||
|
-0.2357022603955158 0.2357022603955158 -0.4714045207910316 0.2357022603955159 -0.2357022603955159 0.4714045207910318 0.2357022603955159 -0.2357022603955159 0.4714045207910318
|
||||||
|
0.2357022603955159 0.23570226039551587 -0.4714045207910318 0.2357022603955159 0.23570226039551587 -0.4714045207910318 0.2357022603955159 0.23570226039551587 -0.4714045207910318
|
|
@ -0,0 +1,13 @@
|
||||||
|
3x3:1_Schmid 3x3:2_Schmid 3x3:3_Schmid 3x3:4_Schmid 3x3:5_Schmid 3x3:6_Schmid 3x3:7_Schmid 3x3:8_Schmid 3x3:9_Schmid
|
||||||
|
-0.4714045207910316 -0.23570226039551578 -0.23570226039551576 0.4714045207910318 0.23570226039551587 0.23570226039551584 0.4714045207910318 0.23570226039551587 0.23570226039551584
|
||||||
|
-0.4714045207910318 0.23570226039551595 0.2357022603955159 -0.4714045207910318 0.23570226039551595 0.2357022603955159 -0.4714045207910318 0.23570226039551595 0.2357022603955159
|
||||||
|
0.47140452079103173 -0.2357022603955159 0.23570226039551584 0.47140452079103173 -0.2357022603955159 0.23570226039551584 -0.4714045207910318 0.23570226039551595 -0.23570226039551587
|
||||||
|
0.4714045207910318 0.23570226039551587 -0.23570226039551595 -0.47140452079103173 -0.23570226039551584 0.2357022603955159 0.4714045207910318 0.23570226039551587 -0.23570226039551595
|
||||||
|
0.2357022603955159 0.4714045207910318 0.23570226039551584 -0.23570226039551587 -0.47140452079103173 -0.23570226039551578 0.2357022603955159 0.4714045207910318 0.23570226039551584
|
||||||
|
-0.23570226039551587 0.47140452079103173 0.23570226039551587 -0.23570226039551587 0.47140452079103173 0.23570226039551587 0.2357022603955159 -0.4714045207910318 -0.2357022603955159
|
||||||
|
0.2357022603955159 -0.4714045207910318 0.23570226039551595 0.2357022603955159 -0.4714045207910318 0.23570226039551595 0.2357022603955159 -0.4714045207910318 0.23570226039551595
|
||||||
|
-0.2357022603955158 -0.4714045207910316 0.23570226039551584 0.2357022603955159 0.4714045207910318 -0.23570226039551595 0.2357022603955159 0.4714045207910318 -0.23570226039551595
|
||||||
|
0.23570226039551587 0.23570226039551584 0.47140452079103173 0.23570226039551587 0.23570226039551584 0.47140452079103173 -0.2357022603955159 -0.23570226039551587 -0.4714045207910318
|
||||||
|
-0.2357022603955159 0.2357022603955159 0.4714045207910318 0.23570226039551587 -0.23570226039551587 -0.47140452079103173 -0.2357022603955159 0.2357022603955159 0.4714045207910318
|
||||||
|
-0.2357022603955158 0.2357022603955158 -0.4714045207910316 0.2357022603955159 -0.2357022603955159 0.4714045207910318 0.2357022603955159 -0.2357022603955159 0.4714045207910318
|
||||||
|
0.2357022603955159 0.23570226039551587 -0.4714045207910318 0.2357022603955159 0.23570226039551587 -0.4714045207910318 0.2357022603955159 0.23570226039551587 -0.4714045207910318
|
|
@ -0,0 +1,34 @@
|
||||||
|
3x3:1_Schmid 3x3:2_Schmid 3x3:3_Schmid 3x3:4_Schmid 3x3:5_Schmid 3x3:6_Schmid 3x3:7_Schmid 3x3:8_Schmid 3x3:9_Schmid
|
||||||
|
0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0
|
||||||
|
0.0 0.0 -0.4999999999999998 0.0 0.0 0.8660254037844388 0.0 0.0 0.0
|
||||||
|
0.0 0.0 -0.5000000000000001 0.0 0.0 -0.8660254037844386 0.0 0.0 0.0
|
||||||
|
0.0 1.0 -5.914589856893347e-17 0.0 0.0 0.0 0.0 0.0 0.0
|
||||||
|
0.4330127018922192 0.24999999999999975 -3.102315069664884e-17 -0.7500000000000002 -0.4330127018922192 5.373367321746164e-17 0.0 0.0 0.0
|
||||||
|
-0.43301270189221935 0.25000000000000006 1.4502014121821253e-18 -0.7499999999999998 0.4330127018922193 2.5118225271075755e-18 0.0 0.0 0.0
|
||||||
|
-0.4330127018922194 -0.7499999999999999 6.059609998111558e-17 0.2500000000000001 0.4330127018922194 -3.498517463593857e-17 0.0 0.0 0.0
|
||||||
|
2.563950248511418e-16 -5.693113199781536e-32 -9.614043519462407e-33 1.0 -2.220446049250313e-16 -3.7496997163046135e-17 0.0 0.0 0.0
|
||||||
|
0.4330127018922194 -0.75 2.8122747872284606e-17 0.25000000000000006 -0.43301270189221935 1.6236676054415494e-17 0.0 0.0 0.0
|
||||||
|
-0.38254602783800284 -0.22086305214969287 -0.23426064283290896 0.6625891564490795 0.38254602783800284 0.40575133560034454 0.0 0.0 0.0
|
||||||
|
0.0 -0.8834522085987724 -0.4685212856658182 0.0 0.0 0.0 0.0 0.0 0.0
|
||||||
|
0.38254602783800307 -0.22086305214969315 -0.23426064283290912 0.6625891564490792 -0.38254602783800296 -0.40575133560034443 0.0 0.0 0.0
|
||||||
|
-0.38254602783800284 -0.22086305214969287 0.23426064283290904 0.6625891564490795 0.38254602783800284 -0.4057513356003447 0.0 0.0 0.0
|
||||||
|
0.0 -0.8834522085987724 0.46852128566581835 0.0 0.0 0.0 0.0 0.0 0.0
|
||||||
|
0.38254602783800307 -0.22086305214969315 0.23426064283290912 0.6625891564490792 -0.38254602783800296 0.40575133560034443 0.0 0.0 0.0
|
||||||
|
-0.39955629492721617 -0.23068393443263763 -0.24467726152216654 3.8591083978971935e-17 2.228057272357889e-17 2.3632116092343994e-17 0.6524726973924442 0.3767052874784087 0.39955629492721606
|
||||||
|
-0.19977814746360817 -0.11534196721631886 -0.12233863076108333 -0.34602590164895664 -0.19977814746360797 -0.21189672420660496 0.6524726973924442 0.3767052874784087 0.39955629492721606
|
||||||
|
0.0 -0.23068393443263785 -0.12233863076108334 0.0 -0.39955629492721617 -0.211896724206605 0.0 0.7534105749568177 0.3995562949272161
|
||||||
|
0.0 0.23068393443263768 0.12233863076108326 0.0 -0.3995562949272162 -0.21189672420660502 0.0 0.7534105749568178 0.39955629492721617
|
||||||
|
-0.199778147463608 0.11534196721631884 0.12233863076108324 0.34602590164895664 -0.1997781474636081 -0.211896724206605 -0.6524726973924442 0.3767052874784089 0.3995562949272161
|
||||||
|
-0.3995562949272161 0.23068393443263774 0.24467726152216654 -3.859108397897193e-17 2.22805727235789e-17 2.3632116092343994e-17 -0.6524726973924441 0.37670528747840887 0.39955629492721606
|
||||||
|
-0.39955629492721617 -0.23068393443263763 0.24467726152216662 -3.8591083978971935e-17 -2.228057272357889e-17 2.3632116092344003e-17 -0.6524726973924442 -0.3767052874784087 0.39955629492721617
|
||||||
|
-0.1997781474636082 -0.11534196721631888 0.1223386307610834 -0.3460259016489568 -0.19977814746360806 0.21189672420660513 -0.6524726973924442 -0.3767052874784087 0.39955629492721617
|
||||||
|
0.0 -0.23068393443263788 0.12233863076108341 0.0 -0.3995562949272163 0.21189672420660516 0.0 -0.7534105749568177 0.3995562949272162
|
||||||
|
0.0 0.2306839344326376 -0.12233863076108324 0.0 -0.3995562949272163 0.21189672420660516 0.0 -0.7534105749568177 0.3995562949272162
|
||||||
|
-0.19977814746360792 0.1153419672163188 -0.12233863076108319 0.34602590164895675 -0.19977814746360814 0.21189672420660505 0.6524726973924441 -0.37670528747840887 0.39955629492721606
|
||||||
|
-0.3995562949272161 0.23068393443263774 -0.24467726152216654 3.859108397897193e-17 -2.22805727235789e-17 2.3632116092343994e-17 0.6524726973924441 -0.37670528747840887 0.39955629492721606
|
||||||
|
-0.11134044285378089 -0.19284730395996755 -0.1363636363636364 -0.19284730395996755 -0.3340213285613424 -0.23618874648666507 0.36363636363636365 0.6298366572977734 0.44536177141512323
|
||||||
|
-0.11134044285378081 0.1928473039599675 0.13636363636363633 0.19284730395996758 -0.3340213285613426 -0.2361887464866651 -0.3636363636363637 0.6298366572977737 0.4453617714151233
|
||||||
|
-0.44536177141512323 9.889017858258314e-17 0.2727272727272727 -4.301519895922435e-17 9.551292858672588e-33 2.634132215859942e-17 -0.7272727272727272 1.6148698540002275e-16 0.44536177141512323
|
||||||
|
-0.1113404428537809 -0.1928473039599676 0.13636363636363644 -0.1928473039599676 -0.33402132856134253 0.23618874648666516 -0.36363636363636365 -0.6298366572977734 0.44536177141512323
|
||||||
|
-0.11134044285378074 0.19284730395996735 -0.13636363636363627 0.19284730395996758 -0.33402132856134253 0.23618874648666516 0.3636363636363636 -0.6298366572977734 0.44536177141512323
|
||||||
|
-0.44536177141512334 9.889017858258316e-17 -0.2727272727272727 4.3015198959224354e-17 -9.55129285867259e-33 2.634132215859942e-17 0.7272727272727273 -1.6148698540002277e-16 0.44536177141512323
|
|
@ -0,0 +1,25 @@
|
||||||
|
3x3:1_Schmid 3x3:2_Schmid 3x3:3_Schmid 3x3:4_Schmid 3x3:5_Schmid 3x3:6_Schmid 3x3:7_Schmid 3x3:8_Schmid 3x3:9_Schmid
|
||||||
|
-0.3743506488634663 -0.21613144789263322 -0.4584840372976439 -0.21613144789263333 -0.12478354962115536 -0.2647058823529411 0.4075413664867946 0.23529411764705865 0.4991341984846217
|
||||||
|
0.0 -1.1032987950073291e-16 -1.1702250894369439e-16 0.0 -0.4991341984846217 -0.5294117647058824 0.0 0.47058823529411753 0.4991341984846218
|
||||||
|
-0.3743506488634663 0.2161314478926334 0.4584840372976439 0.2161314478926334 -0.1247835496211555 -0.2647058823529412 -0.4075413664867947 0.23529411764705888 0.4991341984846218
|
||||||
|
-0.3743506488634663 -0.21613144789263322 0.4584840372976439 -0.2161314478926334 -0.12478354962115538 0.2647058823529412 -0.4075413664867946 -0.23529411764705865 0.4991341984846217
|
||||||
|
0.0 -1.4562117094830577e-16 1.5445457619280876e-16 0.0 -0.4991341984846217 0.5294117647058824 0.0 -0.47058823529411753 0.4991341984846218
|
||||||
|
-0.3743506488634663 0.2161314478926334 -0.4584840372976439 0.21613144789263342 -0.12478354962115551 0.26470588235294124 0.4075413664867947 -0.23529411764705888 0.4991341984846218
|
||||||
|
-0.06998542122237655 -0.1212183053462653 -0.04285714285714286 -0.12121830534626532 -0.20995626366712955 -0.07423074889580901 0.45714285714285724 0.7917946548886295 0.279941684889506
|
||||||
|
-0.06998542122237653 0.12121830534626528 0.04285714285714286 0.12121830534626532 -0.20995626366712958 -0.07423074889580904 -0.45714285714285724 0.7917946548886297 0.2799416848895061
|
||||||
|
-0.27994168488950616 6.2159540823338e-17 0.08571428571428573 -5.407625012016776e-17 1.2007339593759827e-32 1.6557402499691063e-17 -0.9142857142857143 2.0301221021717148e-16 0.27994168488950605
|
||||||
|
-0.0699854212223766 -0.12121830534626538 0.04285714285714291 -0.12121830534626538 -0.20995626366712963 0.07423074889580909 -0.45714285714285724 -0.7917946548886295 0.2799416848895062
|
||||||
|
-0.06998542122237648 0.12121830534626521 -0.04285714285714283 0.12121830534626538 -0.20995626366712966 0.07423074889580906 0.45714285714285724 -0.7917946548886297 0.2799416848895061
|
||||||
|
-0.27994168488950605 6.215954082333798e-17 -0.08571428571428569 5.407625012016776e-17 -1.2007339593759827e-32 1.6557402499691063e-17 0.9142857142857143 -2.0301221021717148e-16 0.27994168488950605
|
||||||
|
0.3104371234477526 0.17923095678901296 0.19010313741609627 0.17923095678901305 0.1034790411492508 0.1097560975609756 -0.6759222663683424 -0.39024390243902424 -0.41391616459700337
|
||||||
|
0.0 7.68600963028337e-17 4.07612214737886e-17 0.0 0.4139161645970035 0.21951219512195125 0.0 -0.7804878048780488 -0.4139161645970034
|
||||||
|
0.31043712344775254 -0.17923095678901305 -0.19010313741609627 -0.17923095678901302 0.10347904114925086 0.1097560975609756 0.6759222663683423 -0.3902439024390244 -0.41391616459700337
|
||||||
|
0.3104371234477527 0.179230956789013 -0.19010313741609638 0.17923095678901313 0.10347904114925086 -0.10975609756097568 0.6759222663683424 0.3902439024390242 -0.4139161645970035
|
||||||
|
0.0 1.3539199431344235e-16 -7.180244797305419e-17 0.0 0.4139161645970036 -0.21951219512195136 0.0 0.7804878048780487 -0.41391616459700353
|
||||||
|
0.3104371234477525 -0.179230956789013 0.19010313741609622 -0.17923095678901313 0.10347904114925092 -0.10975609756097565 -0.6759222663683423 0.3902439024390244 -0.41391616459700337
|
||||||
|
0.11134044285378089 0.19284730395996755 0.1363636363636364 0.19284730395996755 0.3340213285613424 0.23618874648666507 -0.36363636363636365 -0.6298366572977734 -0.44536177141512323
|
||||||
|
0.11134044285378081 -0.1928473039599675 -0.13636363636363633 -0.19284730395996758 0.3340213285613426 0.2361887464866651 0.3636363636363637 -0.6298366572977737 -0.4453617714151233
|
||||||
|
0.44536177141512323 -9.889017858258314e-17 -0.2727272727272727 4.301519895922435e-17 -9.551292858672588e-33 -2.634132215859942e-17 0.7272727272727272 -1.6148698540002275e-16 -0.44536177141512323
|
||||||
|
0.1113404428537809 0.1928473039599676 -0.13636363636363644 0.1928473039599676 0.33402132856134253 -0.23618874648666516 0.36363636363636365 0.6298366572977734 -0.44536177141512323
|
||||||
|
0.11134044285378074 -0.19284730395996735 0.13636363636363627 -0.19284730395996758 0.33402132856134253 -0.23618874648666516 -0.3636363636363636 0.6298366572977734 -0.44536177141512323
|
||||||
|
0.44536177141512334 -9.889017858258316e-17 0.2727272727272727 -4.3015198959224354e-17 9.55129285867259e-33 -2.634132215859942e-17 -0.7272727272727273 1.6148698540002277e-16 -0.44536177141512323
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -1,157 +0,0 @@
|
||||||
import random
|
|
||||||
|
|
||||||
import pytest
|
|
||||||
import numpy as np
|
|
||||||
|
|
||||||
from damask import Rotation
|
|
||||||
from damask import Symmetry
|
|
||||||
|
|
||||||
def in_FZ(system,rho):
|
|
||||||
"""Non-vectorized version of 'in_FZ'."""
|
|
||||||
rho_abs = abs(rho)
|
|
||||||
|
|
||||||
if system == 'cubic':
|
|
||||||
return np.sqrt(2.0)-1.0 >= rho_abs[0] \
|
|
||||||
and np.sqrt(2.0)-1.0 >= rho_abs[1] \
|
|
||||||
and np.sqrt(2.0)-1.0 >= rho_abs[2] \
|
|
||||||
and 1.0 >= rho_abs[0] + rho_abs[1] + rho_abs[2]
|
|
||||||
elif system == 'hexagonal':
|
|
||||||
return 1.0 >= rho_abs[0] and 1.0 >= rho_abs[1] and 1.0 >= rho_abs[2] \
|
|
||||||
and 2.0 >= np.sqrt(3)*rho_abs[0] + rho_abs[1] \
|
|
||||||
and 2.0 >= np.sqrt(3)*rho_abs[1] + rho_abs[0] \
|
|
||||||
and 2.0 >= np.sqrt(3) + rho_abs[2]
|
|
||||||
elif system == 'tetragonal':
|
|
||||||
return 1.0 >= rho_abs[0] and 1.0 >= rho_abs[1] \
|
|
||||||
and np.sqrt(2.0) >= rho_abs[0] + rho_abs[1] \
|
|
||||||
and np.sqrt(2.0) >= rho_abs[2] + 1.0
|
|
||||||
elif system == 'orthorhombic':
|
|
||||||
return 1.0 >= rho_abs[0] and 1.0 >= rho_abs[1] and 1.0 >= rho_abs[2]
|
|
||||||
else:
|
|
||||||
return np.all(np.isfinite(rho_abs))
|
|
||||||
|
|
||||||
|
|
||||||
def in_disorientation_SST(system,rho):
|
|
||||||
"""Non-vectorized version of 'in_Disorientation_SST'."""
|
|
||||||
epsilon = 0.0
|
|
||||||
if system == 'cubic':
|
|
||||||
return rho[0] >= rho[1]+epsilon and rho[1] >= rho[2]+epsilon and rho[2] >= epsilon
|
|
||||||
elif system == 'hexagonal':
|
|
||||||
return rho[0] >= np.sqrt(3)*(rho[1]-epsilon) and rho[1] >= epsilon and rho[2] >= epsilon
|
|
||||||
elif system == 'tetragonal':
|
|
||||||
return rho[0] >= rho[1]-epsilon and rho[1] >= epsilon and rho[2] >= epsilon
|
|
||||||
elif system == 'orthorhombic':
|
|
||||||
return rho[0] >= epsilon and rho[1] >= epsilon and rho[2] >= epsilon
|
|
||||||
else:
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
def in_SST(system,vector,proper = False):
|
|
||||||
"""Non-vectorized version of 'in_SST'."""
|
|
||||||
if system == 'cubic':
|
|
||||||
basis = {'improper':np.array([ [-1. , 0. , 1. ],
|
|
||||||
[ np.sqrt(2.) , -np.sqrt(2.) , 0. ],
|
|
||||||
[ 0. , np.sqrt(3.) , 0. ] ]),
|
|
||||||
'proper':np.array([ [ 0. , -1. , 1. ],
|
|
||||||
[-np.sqrt(2.) , np.sqrt(2.) , 0. ],
|
|
||||||
[ np.sqrt(3.) , 0. , 0. ] ]),
|
|
||||||
}
|
|
||||||
elif system == 'hexagonal':
|
|
||||||
basis = {'improper':np.array([ [ 0. , 0. , 1. ],
|
|
||||||
[ 1. , -np.sqrt(3.) , 0. ],
|
|
||||||
[ 0. , 2. , 0. ] ]),
|
|
||||||
'proper':np.array([ [ 0. , 0. , 1. ],
|
|
||||||
[-1. , np.sqrt(3.) , 0. ],
|
|
||||||
[ np.sqrt(3.) , -1. , 0. ] ]),
|
|
||||||
}
|
|
||||||
elif system == 'tetragonal':
|
|
||||||
basis = {'improper':np.array([ [ 0. , 0. , 1. ],
|
|
||||||
[ 1. , -1. , 0. ],
|
|
||||||
[ 0. , np.sqrt(2.) , 0. ] ]),
|
|
||||||
'proper':np.array([ [ 0. , 0. , 1. ],
|
|
||||||
[-1. , 1. , 0. ],
|
|
||||||
[ np.sqrt(2.) , 0. , 0. ] ]),
|
|
||||||
}
|
|
||||||
elif system == 'orthorhombic':
|
|
||||||
basis = {'improper':np.array([ [ 0., 0., 1.],
|
|
||||||
[ 1., 0., 0.],
|
|
||||||
[ 0., 1., 0.] ]),
|
|
||||||
'proper':np.array([ [ 0., 0., 1.],
|
|
||||||
[-1., 0., 0.],
|
|
||||||
[ 0., 1., 0.] ]),
|
|
||||||
}
|
|
||||||
else:
|
|
||||||
return True
|
|
||||||
|
|
||||||
v = np.array(vector,dtype=float)
|
|
||||||
if proper:
|
|
||||||
theComponents = np.around(np.dot(basis['improper'],v),12)
|
|
||||||
inSST = np.all(theComponents >= 0.0)
|
|
||||||
if not inSST:
|
|
||||||
theComponents = np.around(np.dot(basis['proper'],v),12)
|
|
||||||
inSST = np.all(theComponents >= 0.0)
|
|
||||||
else:
|
|
||||||
v[2] = abs(v[2])
|
|
||||||
theComponents = np.around(np.dot(basis['improper'],v),12)
|
|
||||||
inSST = np.all(theComponents >= 0.0)
|
|
||||||
|
|
||||||
return inSST
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def set_of_rodrigues(set_of_quaternions):
|
|
||||||
return Rotation(set_of_quaternions).as_Rodrigues(vector=True)[:200]
|
|
||||||
|
|
||||||
class TestSymmetry:
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('system',Symmetry.crystal_systems)
|
|
||||||
def test_in_FZ_vectorize(self,set_of_rodrigues,system):
|
|
||||||
result = Symmetry(system).in_FZ(set_of_rodrigues.reshape(50,4,3)).reshape(200)
|
|
||||||
for i,r in enumerate(result):
|
|
||||||
assert r == in_FZ(system,set_of_rodrigues[i])
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('system',Symmetry.crystal_systems)
|
|
||||||
def test_in_disorientation_SST_vectorize(self,set_of_rodrigues,system):
|
|
||||||
result = Symmetry(system).in_disorientation_SST(set_of_rodrigues.reshape(50,4,3)).reshape(200)
|
|
||||||
for i,r in enumerate(result):
|
|
||||||
assert r == in_disorientation_SST(system,set_of_rodrigues[i])
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('proper',[True,False])
|
|
||||||
@pytest.mark.parametrize('system',Symmetry.crystal_systems)
|
|
||||||
def test_in_SST_vectorize(self,system,proper):
|
|
||||||
vecs = np.random.rand(20,4,3)
|
|
||||||
result = Symmetry(system).in_SST(vecs,proper).reshape(20*4)
|
|
||||||
for i,r in enumerate(result):
|
|
||||||
assert r == in_SST(system,vecs.reshape(20*4,3)[i],proper)
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('invalid_symmetry',['fcc','bcc','hello'])
|
|
||||||
def test_invalid_symmetry(self,invalid_symmetry):
|
|
||||||
with pytest.raises(KeyError):
|
|
||||||
s = Symmetry(invalid_symmetry) # noqa
|
|
||||||
|
|
||||||
def test_equal(self):
|
|
||||||
symmetry = random.choice(Symmetry.crystal_systems)
|
|
||||||
print(symmetry)
|
|
||||||
assert Symmetry(symmetry) == Symmetry(symmetry)
|
|
||||||
|
|
||||||
def test_not_equal(self):
|
|
||||||
symmetries = random.sample(Symmetry.crystal_systems,k=2)
|
|
||||||
assert Symmetry(symmetries[0]) != Symmetry(symmetries[1])
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('system',Symmetry.crystal_systems)
|
|
||||||
def test_in_FZ(self,system):
|
|
||||||
assert Symmetry(system).in_FZ(np.zeros(3))
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('system',Symmetry.crystal_systems)
|
|
||||||
def test_in_disorientation_SST(self,system):
|
|
||||||
assert Symmetry(system).in_disorientation_SST(np.zeros(3))
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('system',Symmetry.crystal_systems)
|
|
||||||
@pytest.mark.parametrize('proper',[True,False])
|
|
||||||
def test_in_SST(self,system,proper):
|
|
||||||
assert Symmetry(system).in_SST(np.zeros(3),proper)
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('function',['in_FZ','in_disorientation_SST','in_SST'])
|
|
||||||
def test_invalid_argument(self,function):
|
|
||||||
s = Symmetry() # noqa
|
|
||||||
with pytest.raises(ValueError):
|
|
||||||
eval(f's.{function}(np.ones(4))')
|
|
|
@ -1,131 +1,536 @@
|
||||||
import os
|
|
||||||
from itertools import permutations
|
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
from itertools import permutations
|
||||||
|
|
||||||
from damask import Table
|
|
||||||
from damask import Rotation
|
from damask import Rotation
|
||||||
from damask import Orientation
|
from damask import Orientation
|
||||||
from damask import Lattice
|
from damask import Table
|
||||||
|
from damask import lattice
|
||||||
n = 1000
|
from damask import util
|
||||||
|
|
||||||
def IPF_color(orientation,direction):
|
|
||||||
"""TSL color of inverse pole figure for given axis (non-vectorized)."""
|
|
||||||
for o in orientation.equivalent:
|
|
||||||
pole = o.rotation@direction
|
|
||||||
inSST,color = orientation.lattice.in_SST(pole,color=True)
|
|
||||||
if inSST: break
|
|
||||||
|
|
||||||
return color
|
|
||||||
|
|
||||||
def inverse_pole(orientation,axis,proper=False,SST=True):
|
|
||||||
if SST:
|
|
||||||
for eq in orientation.equivalent:
|
|
||||||
pole = eq.rotation @ axis/np.linalg.norm(axis)
|
|
||||||
if orientation.lattice.in_SST(pole,proper=proper):
|
|
||||||
return pole
|
|
||||||
else:
|
|
||||||
return orientation.rotation @ axis/np.linalg.norm(axis)
|
|
||||||
|
|
||||||
|
|
||||||
@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 reference_dir_base/'Rotation'
|
return reference_dir_base/'Orientation'
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def set_of_rodrigues(set_of_quaternions):
|
||||||
|
return Rotation(set_of_quaternions).as_Rodrigues()[:200]
|
||||||
|
|
||||||
|
|
||||||
class TestOrientation:
|
class TestOrientation:
|
||||||
|
|
||||||
@pytest.mark.parametrize('model',['Bain','KS','GT','GT_prime','NW','Pitsch'])
|
@pytest.mark.parametrize('lattice',Orientation.crystal_families)
|
||||||
@pytest.mark.parametrize('lattice',['fcc','bcc'])
|
@pytest.mark.parametrize('shape',[None,5,(4,6)])
|
||||||
def test_relationship_vectorize(self,set_of_quaternions,lattice,model):
|
def test_equal(self,lattice,shape):
|
||||||
result = Orientation(set_of_quaternions[:200].reshape(50,4,4),lattice).related(model)
|
R = Rotation.from_random(shape)
|
||||||
ref_qu = result.rotation.quaternion.reshape(-1,200,4)
|
assert Orientation(R,lattice) == Orientation(R,lattice)
|
||||||
for i in range(200):
|
|
||||||
single = Orientation(set_of_quaternions[i],lattice).related(model).rotation.quaternion
|
|
||||||
assert np.allclose(ref_qu[:,i,:],single)
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('lattice',Lattice.lattices)
|
@pytest.mark.parametrize('lattice',Orientation.crystal_families)
|
||||||
def test_IPF_vectorize(self,set_of_quaternions,lattice):
|
@pytest.mark.parametrize('shape',[None,5,(4,6)])
|
||||||
direction = np.random.random(3)*2.0-1
|
def test_unequal(self,lattice,shape):
|
||||||
oris = Orientation(Rotation(set_of_quaternions),lattice)[:200]
|
R = Rotation.from_random(shape)
|
||||||
for i,color in enumerate(oris.IPF_color(direction)):
|
assert not(Orientation(R,lattice) != Orientation(R,lattice))
|
||||||
assert np.allclose(color,IPF_color(oris[i],direction))
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('SST',[False,True])
|
@pytest.mark.parametrize('a,b',[
|
||||||
|
(dict(rotation=[1,0,0,0]),
|
||||||
|
dict(rotation=[0.5,0.5,0.5,0.5])),
|
||||||
|
|
||||||
|
(dict(rotation=[1,0,0,0],lattice='cubic'),
|
||||||
|
dict(rotation=[1,0,0,0],lattice='hexagonal')),
|
||||||
|
|
||||||
|
(dict(rotation=[1,0,0,0],lattice='cF',a=1),
|
||||||
|
dict(rotation=[1,0,0,0],lattice='cF',a=2)),
|
||||||
|
])
|
||||||
|
def test_nonequal(self,a,b):
|
||||||
|
assert Orientation(**a) != Orientation(**b)
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('kwargs',[
|
||||||
|
dict(lattice='aP', alpha=np.pi/4,beta=np.pi/3, ),
|
||||||
|
dict(lattice='mP', c=1.2,alpha=np.pi/4, gamma=np.pi/2),
|
||||||
|
dict(lattice='oP', c=1.2,alpha=np.pi/4, ),
|
||||||
|
dict(lattice='oS',a=1.0, c=2.0,alpha=np.pi/2,beta=np.pi/3, ),
|
||||||
|
dict(lattice='tP',a=1.0,b=1.2, ),
|
||||||
|
dict(lattice='tI', alpha=np.pi/3, ),
|
||||||
|
dict(lattice='hP', gamma=np.pi/2),
|
||||||
|
dict(lattice='cI',a=1.0, c=2.0,alpha=np.pi/2,beta=np.pi/2, ),
|
||||||
|
dict(lattice='cF', beta=np.pi/3, ),
|
||||||
|
])
|
||||||
|
def test_invalid_init(self,kwargs):
|
||||||
|
with pytest.raises(ValueError):
|
||||||
|
Orientation(**kwargs).parameters # noqa
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('kwargs',[
|
||||||
|
dict(lattice='aP',a=1.0,b=1.1,c=1.2,alpha=np.pi/4,beta=np.pi/3,gamma=np.pi/2),
|
||||||
|
dict(lattice='mP',a=1.0,b=1.1,c=1.2, beta=np.pi/3 ),
|
||||||
|
dict(lattice='oS',a=1.0,b=1.1,c=1.2, ),
|
||||||
|
dict(lattice='tI',a=1.0, c=1.2, ),
|
||||||
|
dict(lattice='hP',a=1.0 ),
|
||||||
|
dict(lattice='cI',a=1.0, ),
|
||||||
|
])
|
||||||
|
def test_repr(self,kwargs):
|
||||||
|
o = Orientation.from_random(**kwargs)
|
||||||
|
assert isinstance(o.__repr__(),str)
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('kwargs',[
|
||||||
|
dict(lattice='aP',a=1.0,b=1.1,c=1.2,alpha=np.pi/4,beta=np.pi/3,gamma=np.pi/2),
|
||||||
|
dict(lattice='mP',a=1.0,b=1.1,c=1.2, beta=np.pi/3 ),
|
||||||
|
dict(lattice='oS',a=1.0,b=1.1,c=1.2, ),
|
||||||
|
dict(lattice='tI',a=1.0, c=1.2, ),
|
||||||
|
dict(lattice='hP',a=1.0 ),
|
||||||
|
dict(lattice='cI',a=1.0, ),
|
||||||
|
])
|
||||||
|
def test_copy(self,kwargs):
|
||||||
|
o = Orientation.from_random(**kwargs)
|
||||||
|
p = o.copy(rotation=Rotation.from_random())
|
||||||
|
assert o != p
|
||||||
|
|
||||||
|
def test_from_quaternion(self):
|
||||||
|
assert np.all(Orientation.from_quaternion(q=np.array([1,0,0,0]),lattice='triclinic').as_matrix()
|
||||||
|
== np.eye(3))
|
||||||
|
|
||||||
|
def test_from_Eulers(self):
|
||||||
|
assert np.all(Orientation.from_Eulers(phi=np.zeros(3),lattice='triclinic').as_matrix()
|
||||||
|
== np.eye(3))
|
||||||
|
|
||||||
|
def test_from_axis_angle(self):
|
||||||
|
assert np.all(Orientation.from_axis_angle(axis_angle=[1,0,0,0],lattice='triclinic').as_matrix()
|
||||||
|
== np.eye(3))
|
||||||
|
|
||||||
|
def test_from_basis(self):
|
||||||
|
assert np.all(Orientation.from_basis(basis=np.eye(3),lattice='triclinic').as_matrix()
|
||||||
|
== np.eye(3))
|
||||||
|
|
||||||
|
def test_from_matrix(self):
|
||||||
|
assert np.all(Orientation.from_matrix(R=np.eye(3),lattice='triclinic').as_matrix()
|
||||||
|
== np.eye(3))
|
||||||
|
|
||||||
|
def test_from_Rodrigues(self):
|
||||||
|
assert np.all(Orientation.from_Rodrigues(rho=np.array([0,0,1,0]),lattice='triclinic').as_matrix()
|
||||||
|
== np.eye(3))
|
||||||
|
|
||||||
|
def test_from_homochoric(self):
|
||||||
|
assert np.all(Orientation.from_homochoric(h=np.zeros(3),lattice='triclinic').as_matrix()
|
||||||
|
== np.eye(3))
|
||||||
|
|
||||||
|
def test_from_cubochoric(self):
|
||||||
|
assert np.all(Orientation.from_cubochoric(c=np.zeros(3),lattice='triclinic').as_matrix()
|
||||||
|
== np.eye(3))
|
||||||
|
|
||||||
|
def test_from_spherical_component(self):
|
||||||
|
assert np.all(Orientation.from_spherical_component(center=Rotation(),
|
||||||
|
sigma=0.0,N=1,lattice='triclinic').as_matrix()
|
||||||
|
== np.eye(3))
|
||||||
|
|
||||||
|
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)
|
||||||
|
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
|
||||||
|
== r.quaternion)
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('kwargs',[
|
||||||
|
dict(lattice='aP',a=1.0,b=1.1,c=1.2,alpha=np.pi/4.5,beta=np.pi/3.5,gamma=np.pi/2.5),
|
||||||
|
dict(lattice='mP',a=1.0,b=1.1,c=1.2, beta=np.pi/3.5),
|
||||||
|
dict(lattice='oS',a=1.0,b=1.1,c=1.2,),
|
||||||
|
dict(lattice='tI',a=1.0, c=1.2,),
|
||||||
|
dict(lattice='hP',a=1.0 ),
|
||||||
|
dict(lattice='cI',a=1.0, ),
|
||||||
|
])
|
||||||
|
def test_from_direction(self,kwargs):
|
||||||
|
for a,b in np.random.random((10,2,3)):
|
||||||
|
c = np.cross(b,a)
|
||||||
|
if np.all(np.isclose(c,0)): continue
|
||||||
|
o = Orientation.from_directions(uvw=a,hkl=c,**kwargs)
|
||||||
|
x = o.to_pole(uvw=a)
|
||||||
|
z = o.to_pole(hkl=c)
|
||||||
|
assert np.isclose(np.dot(x/np.linalg.norm(x),np.array([1,0,0])),1) \
|
||||||
|
and np.isclose(np.dot(z/np.linalg.norm(z),np.array([0,0,1])),1)
|
||||||
|
|
||||||
|
|
||||||
|
def test_negative_angle(self):
|
||||||
|
with pytest.raises(ValueError):
|
||||||
|
Orientation(lattice='aP',a=1,b=2,c=3,alpha=45,beta=45,gamma=-45,degrees=True) # noqa
|
||||||
|
|
||||||
|
def test_excess_angle(self):
|
||||||
|
with pytest.raises(ValueError):
|
||||||
|
Orientation(lattice='aP',a=1,b=2,c=3,alpha=45,beta=45,gamma=90.0001,degrees=True) # noqa
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('lattice',Orientation.crystal_families)
|
||||||
|
@pytest.mark.parametrize('angle',[10,20,30,40])
|
||||||
|
def test_average(self,angle,lattice):
|
||||||
|
o = Orientation.from_axis_angle(lattice=lattice,axis_angle=[[0,0,1,10],[0,0,1,angle]],degrees=True)
|
||||||
|
avg_angle = o.average().as_axis_angle(degrees=True,pair=True)[1]
|
||||||
|
assert np.isclose(avg_angle,10+(angle-10)/2.)
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('lattice',Orientation.crystal_families)
|
||||||
|
def test_reduced_equivalent(self,lattice):
|
||||||
|
i = Orientation(lattice=lattice)
|
||||||
|
o = Orientation.from_random(lattice=lattice)
|
||||||
|
eq = o.equivalent
|
||||||
|
FZ = np.argmin(abs(eq.misorientation(i.broadcast_to(len(eq))).as_axis_angle(pair=True)[1]))
|
||||||
|
assert o.reduced == eq[FZ]
|
||||||
|
|
||||||
|
@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)
|
||||||
|
|
||||||
|
d,ops = o.disorientation(p,return_operators=True)
|
||||||
|
|
||||||
|
for n in range(N):
|
||||||
|
assert np.allclose(d[n].as_quaternion(),
|
||||||
|
o[n].equivalent[ops[n][0]]
|
||||||
|
.misorientation(p[n].equivalent[ops[n][1]])
|
||||||
|
.as_quaternion()) \
|
||||||
|
or np.allclose((~d)[n].as_quaternion(),
|
||||||
|
o[n].equivalent[ops[n][0]]
|
||||||
|
.misorientation(p[n].equivalent[ops[n][1]])
|
||||||
|
.as_quaternion())
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('lattice',Orientation.crystal_families)
|
||||||
|
@pytest.mark.parametrize('a,b',[
|
||||||
|
((2,3,2),(2,3,2)),
|
||||||
|
((2,2),(4,4)),
|
||||||
|
((3,1),(1,3)),
|
||||||
|
(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)
|
||||||
|
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):])]) \
|
||||||
|
== o.disorientation(p)[tuple(loc)]
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('lattice',Orientation.crystal_families)
|
||||||
|
def test_disorientation360(self,lattice):
|
||||||
|
o_1 = Orientation(Rotation(),lattice)
|
||||||
|
o_2 = Orientation.from_Eulers(lattice=lattice,phi=[360,0,0],degrees=True)
|
||||||
|
assert np.allclose((o_1.disorientation(o_2)).as_matrix(),np.eye(3))
|
||||||
|
|
||||||
|
@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)
|
||||||
|
for r, theO in zip(o.reduced.flatten(),o.flatten()):
|
||||||
|
assert r == theO.reduced
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('lattice',Orientation.crystal_families)
|
||||||
|
@pytest.mark.parametrize('shape',[(1),(2,3),(4,3,2)])
|
||||||
|
@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])
|
||||||
@pytest.mark.parametrize('lattice',Lattice.lattices)
|
def test_to_SST_vectorization(self,lattice,shape,vector,proper):
|
||||||
def test_inverse_pole_vectorize(self,set_of_quaternions,lattice,SST,proper):
|
o = Orientation.from_random(lattice=lattice,shape=shape,seed=0)
|
||||||
axis = np.random.random(3)*2.0-1
|
for r, theO in zip(o.to_SST(vector=vector,proper=proper).reshape((-1,3)),o.flatten()):
|
||||||
oris = Orientation(Rotation(set_of_quaternions),lattice)[:200]
|
assert np.allclose(r,theO.to_SST(vector=vector,proper=proper))
|
||||||
for i,pole in enumerate(oris.inverse_pole(axis,SST=SST)):
|
|
||||||
assert np.allclose(pole,inverse_pole(oris[i],axis,SST=SST))
|
@pytest.mark.parametrize('lattice',Orientation.crystal_families)
|
||||||
|
@pytest.mark.parametrize('shape',[(1),(2,3),(4,3,2)])
|
||||||
|
@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)
|
||||||
|
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))
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('lattice',Orientation.crystal_families)
|
||||||
|
@pytest.mark.parametrize('a,b',[
|
||||||
|
((2,3,2),(2,3,2)),
|
||||||
|
((2,2),(4,4)),
|
||||||
|
((3,1),(1,3)),
|
||||||
|
(None,(3,)),
|
||||||
|
])
|
||||||
|
def test_to_SST_blending(self,lattice,a,b):
|
||||||
|
o = Orientation.from_random(lattice=lattice,shape=a,seed=0)
|
||||||
|
v = np.random.random(b+(3,))
|
||||||
|
blend = util.shapeblender(o.shape,b)
|
||||||
|
for loc in np.random.randint(0,blend,(10,len(blend))):
|
||||||
|
print(f'{a}/{b} @ {loc}')
|
||||||
|
print(o[tuple(loc[:len(o.shape)])].to_SST(v[tuple(loc[-len(b):])]))
|
||||||
|
print(o.to_SST(v)[tuple(loc)])
|
||||||
|
assert np.allclose(o[tuple(loc[:len(o.shape)])].to_SST(v[tuple(loc[-len(b):])]),
|
||||||
|
o.to_SST(v)[tuple(loc)])
|
||||||
|
|
||||||
@pytest.mark.parametrize('color',[{'label':'red', 'RGB':[1,0,0],'direction':[0,0,1]},
|
@pytest.mark.parametrize('color',[{'label':'red', 'RGB':[1,0,0],'direction':[0,0,1]},
|
||||||
{'label':'green','RGB':[0,1,0],'direction':[0,1,1]},
|
{'label':'green','RGB':[0,1,0],'direction':[0,1,1]},
|
||||||
{'label':'blue', 'RGB':[0,0,1],'direction':[1,1,1]}])
|
{'label':'blue', 'RGB':[0,0,1],'direction':[1,1,1]}])
|
||||||
@pytest.mark.parametrize('lattice',['fcc','bcc'])
|
@pytest.mark.parametrize('proper',[True,False])
|
||||||
def test_IPF_cubic(self,color,lattice):
|
def test_IPF_cubic(self,color,proper):
|
||||||
cube = Orientation(Rotation(),lattice)
|
cube = Orientation(lattice='cubic')
|
||||||
for direction in set(permutations(np.array(color['direction']))):
|
for direction in set(permutations(np.array(color['direction']))):
|
||||||
assert np.allclose(cube.IPF_color(np.array(direction)),np.array(color['RGB']))
|
assert np.allclose(np.array(color['RGB']),
|
||||||
|
cube.IPF_color(cube.to_SST(vector=np.array(direction),proper=proper),proper=proper))
|
||||||
|
|
||||||
@pytest.mark.parametrize('lattice',Lattice.lattices)
|
@pytest.mark.parametrize('lattice',Orientation.crystal_families)
|
||||||
def test_IPF_equivalent(self,set_of_quaternions,lattice):
|
@pytest.mark.parametrize('proper',[True,False])
|
||||||
direction = np.random.random(3)*2.0-1
|
def test_IPF_equivalent(self,set_of_quaternions,lattice,proper):
|
||||||
for ori in Orientation(Rotation(set_of_quaternions),lattice)[:200]:
|
direction = np.random.random(3)*2.0-1.0
|
||||||
color = ori.IPF_color(direction)
|
o = Orientation(rotation=set_of_quaternions,lattice=lattice).equivalent
|
||||||
for equivalent in ori.equivalent:
|
color = o.IPF_color(o.to_SST(vector=direction,proper=proper),proper=proper)
|
||||||
assert np.allclose(color,equivalent.IPF_color(direction))
|
assert np.allclose(np.broadcast_to(color[0,...],color.shape),color)
|
||||||
|
|
||||||
@pytest.mark.parametrize('lattice',Lattice.lattices)
|
@pytest.mark.parametrize('lattice',Orientation.crystal_families)
|
||||||
def test_reduced(self,set_of_quaternions,lattice):
|
def test_in_FZ_vectorization(self,set_of_rodrigues,lattice):
|
||||||
oris = Orientation(Rotation(set_of_quaternions),lattice)
|
result = Orientation.from_Rodrigues(rho=set_of_rodrigues.reshape((50,4,-1)),lattice=lattice).in_FZ.reshape(-1)
|
||||||
reduced = oris.reduced
|
for r,rho in zip(result,set_of_rodrigues[:len(result)]):
|
||||||
assert np.all(reduced.in_FZ) and oris.rotation.shape == reduced.rotation.shape
|
assert r == Orientation.from_Rodrigues(rho=rho,lattice=lattice).in_FZ
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('lattice',Orientation.crystal_families)
|
||||||
|
def test_in_disorientation_FZ_vectorization(self,set_of_rodrigues,lattice):
|
||||||
|
result = Orientation.from_Rodrigues(rho=set_of_rodrigues.reshape((50,4,-1)),
|
||||||
|
lattice=lattice).in_disorientation_FZ.reshape(-1)
|
||||||
|
for r,rho in zip(result,set_of_rodrigues[:len(result)]):
|
||||||
|
assert r == Orientation.from_Rodrigues(rho=rho,lattice=lattice).in_disorientation_FZ
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('proper',[True,False])
|
||||||
|
@pytest.mark.parametrize('lattice',Orientation.crystal_families)
|
||||||
|
def test_in_SST_vectorization(self,lattice,proper):
|
||||||
|
vecs = np.random.rand(20,4,3)
|
||||||
|
result = Orientation(lattice=lattice).in_SST(vecs,proper).flatten()
|
||||||
|
for r,v in zip(result,vecs.reshape((-1,3))):
|
||||||
|
assert np.all(r == Orientation(lattice=lattice).in_SST(v,proper))
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('invalid_lattice',['fcc','bcc','hello'])
|
||||||
|
def test_invalid_lattice_init(self,invalid_lattice):
|
||||||
|
with pytest.raises(KeyError):
|
||||||
|
Orientation(lattice=invalid_lattice) # noqa
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('invalid_family',[None,'fcc','bcc','hello'])
|
||||||
|
def test_invalid_symmetry_family(self,invalid_family):
|
||||||
|
with pytest.raises(KeyError):
|
||||||
|
o = Orientation(lattice='cubic')
|
||||||
|
o.family = invalid_family
|
||||||
|
o.symmetry_operations # noqa
|
||||||
|
|
||||||
|
def test_missing_symmetry_equivalent(self):
|
||||||
|
with pytest.raises(ValueError):
|
||||||
|
Orientation(lattice=None).equivalent # noqa
|
||||||
|
|
||||||
|
def test_missing_symmetry_reduced(self):
|
||||||
|
with pytest.raises(ValueError):
|
||||||
|
Orientation(lattice=None).reduced # noqa
|
||||||
|
|
||||||
|
def test_missing_symmetry_in_FZ(self):
|
||||||
|
with pytest.raises(ValueError):
|
||||||
|
Orientation(lattice=None).in_FZ # noqa
|
||||||
|
|
||||||
|
def test_missing_symmetry_in_disorientation_FZ(self):
|
||||||
|
with pytest.raises(ValueError):
|
||||||
|
Orientation(lattice=None).in_disorientation_FZ # noqa
|
||||||
|
|
||||||
|
def test_missing_symmetry_disorientation(self):
|
||||||
|
with pytest.raises(ValueError):
|
||||||
|
Orientation(lattice=None).disorientation(Orientation(lattice=None)) # noqa
|
||||||
|
|
||||||
|
def test_missing_symmetry_average(self):
|
||||||
|
with pytest.raises(ValueError):
|
||||||
|
Orientation(lattice=None).average() # noqa
|
||||||
|
|
||||||
|
def test_missing_symmetry_to_SST(self):
|
||||||
|
with pytest.raises(ValueError):
|
||||||
|
Orientation(lattice=None).to_SST(np.zeros(3)) # noqa
|
||||||
|
|
||||||
|
def test_missing_symmetry_immutable(self):
|
||||||
|
with pytest.raises(KeyError):
|
||||||
|
Orientation(lattice=None).immutable # noqa
|
||||||
|
|
||||||
|
def test_missing_symmetry_basis_real(self):
|
||||||
|
with pytest.raises(KeyError):
|
||||||
|
Orientation(lattice=None).basis_real # noqa
|
||||||
|
|
||||||
|
def test_missing_symmetry_basis_reciprocal(self):
|
||||||
|
with pytest.raises(KeyError):
|
||||||
|
Orientation(lattice=None).basis_reciprocal # noqa
|
||||||
|
|
||||||
|
def test_double_Bravais_to_Miller(self):
|
||||||
|
with pytest.raises(KeyError):
|
||||||
|
Orientation.Bravais_to_Miller(uvtw=np.ones(4),hkil=np.ones(4)) # noqa
|
||||||
|
|
||||||
|
def test_double_Miller_to_Bravais(self):
|
||||||
|
with pytest.raises(KeyError):
|
||||||
|
Orientation.Miller_to_Bravais(uvw=np.ones(4),hkl=np.ones(4)) # noqa
|
||||||
|
|
||||||
|
def test_double_to_lattice(self):
|
||||||
|
with pytest.raises(KeyError):
|
||||||
|
Orientation().to_lattice(direction=np.ones(3),plane=np.ones(3)) # noqa
|
||||||
|
|
||||||
|
def test_double_to_frame(self):
|
||||||
|
with pytest.raises(KeyError):
|
||||||
|
Orientation().to_frame(uvw=np.ones(3),hkl=np.ones(3)) # noqa
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('relation',[None,'Peter','Paul'])
|
||||||
|
def test_unknown_relation(self,relation):
|
||||||
|
with pytest.raises(KeyError):
|
||||||
|
Orientation(lattice='cF').related(relation) # noqa
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('relation,lattice,a,b,c,alpha,beta,gamma',
|
||||||
|
[
|
||||||
|
('Bain', 'aP',0.5,2.0,3.0,0.8,0.5,1.2),
|
||||||
|
('KS', 'mP',1.0,2.0,3.0,np.pi/2,0.5,np.pi/2),
|
||||||
|
('Pitsch', 'oI',0.5,1.5,3.0,np.pi/2,np.pi/2,np.pi/2),
|
||||||
|
('Burgers','tP',0.5,0.5,3.0,np.pi/2,np.pi/2,np.pi/2),
|
||||||
|
('GT', 'hP',1.0,None,1.6,np.pi/2,np.pi/2,2*np.pi/3),
|
||||||
|
('Burgers','cF',1.0,1.0,None,np.pi/2,np.pi/2,np.pi/2),
|
||||||
|
])
|
||||||
|
def test_unknown_relation_lattice(self,relation,lattice,a,b,c,alpha,beta,gamma):
|
||||||
|
with pytest.raises(KeyError):
|
||||||
|
Orientation(lattice=lattice,
|
||||||
|
a=a,b=b,c=c,
|
||||||
|
alpha=alpha,beta=beta,gamma=gamma).related(relation) # noqa
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('lattice',Orientation.crystal_families)
|
||||||
|
@pytest.mark.parametrize('proper',[True,False])
|
||||||
|
def test_in_SST(self,lattice,proper):
|
||||||
|
assert Orientation(lattice=lattice).in_SST(np.zeros(3),proper)
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('function',['in_SST','IPF_color'])
|
||||||
|
def test_invalid_argument(self,function):
|
||||||
|
o = Orientation(lattice='cubic') # noqa
|
||||||
|
with pytest.raises(ValueError):
|
||||||
|
eval(f'o.{function}(np.ones(4))')
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('model',lattice.relations)
|
||||||
|
def test_relationship_definition(self,model):
|
||||||
|
m,o = list(lattice.relations[model])
|
||||||
|
assert lattice.relations[model][m].shape[:-1] == lattice.relations[model][o].shape[:-1]
|
||||||
|
|
||||||
@pytest.mark.parametrize('model',['Bain','KS','GT','GT_prime','NW','Pitsch'])
|
@pytest.mark.parametrize('model',['Bain','KS','GT','GT_prime','NW','Pitsch'])
|
||||||
@pytest.mark.parametrize('lattice',['fcc','bcc'])
|
@pytest.mark.parametrize('lattice',['cF','cI'])
|
||||||
|
def test_relationship_vectorize(self,set_of_quaternions,lattice,model):
|
||||||
|
r = Orientation(rotation=set_of_quaternions[:200].reshape((50,4,4)),lattice=lattice).related(model)
|
||||||
|
for i in range(200):
|
||||||
|
assert r.reshape((-1,200))[:,i] == Orientation(set_of_quaternions[i],lattice).related(model)
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('model',['Bain','KS','GT','GT_prime','NW','Pitsch'])
|
||||||
|
@pytest.mark.parametrize('lattice',['cF','cI'])
|
||||||
def test_relationship_forward_backward(self,model,lattice):
|
def test_relationship_forward_backward(self,model,lattice):
|
||||||
ori = Orientation(Rotation.from_random(),lattice)
|
o = Orientation.from_random(lattice=lattice)
|
||||||
for i,r in enumerate(ori.related(model)):
|
for i,r in enumerate(o.related(model)):
|
||||||
ori2 = r.related(model)[i]
|
assert o.disorientation(r.related(model)[i]).as_axis_angle(degrees=True,pair=True)[1]<1.0e-5
|
||||||
misorientation = ori.rotation.misorientation(ori2.rotation)
|
|
||||||
assert misorientation.as_axis_angle(degrees=True)[3]<1.0e-5
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('model',['Bain','KS','GT','GT_prime','NW','Pitsch'])
|
@pytest.mark.parametrize('model',['Bain','KS','GT','GT_prime','NW','Pitsch'])
|
||||||
@pytest.mark.parametrize('lattice',['fcc','bcc'])
|
@pytest.mark.parametrize('lattice',['cF','cI'])
|
||||||
def test_relationship_reference(self,update,reference_dir,model,lattice):
|
def test_relationship_reference(self,update,reference_dir,model,lattice):
|
||||||
reference = os.path.join(reference_dir,f'{lattice}_{model}.txt')
|
reference = reference_dir/f'{lattice}_{model}.txt'
|
||||||
ori = Orientation(Rotation(),lattice)
|
o = Orientation(lattice=lattice)
|
||||||
eu = np.array([o.rotation.as_Eulers(degrees=True) for o in ori.related(model)])
|
eu = o.related(model).as_Eulers(degrees=True)
|
||||||
if update:
|
if update:
|
||||||
coords = np.array([(1,i+1) for i,x in enumerate(eu)])
|
coords = np.array([(1,i+1) for i,x in enumerate(eu)])
|
||||||
table = Table(eu,{'Eulers':(3,)})
|
Table(eu,{'Eulers':(3,)})\
|
||||||
table = table.add('pos',coords)
|
.add('pos',coords)\
|
||||||
table.save(reference)
|
.save(reference)
|
||||||
assert np.allclose(eu,Table.load(reference).get('Eulers'))
|
assert np.allclose(eu,Table.load(reference).get('Eulers'))
|
||||||
|
|
||||||
@pytest.mark.parametrize('lattice',Lattice.lattices)
|
def test_basis_real(self):
|
||||||
def test_disorientation360(self,lattice):
|
for gamma in np.random.random(2**8)*np.pi:
|
||||||
R_1 = Orientation(Rotation(),lattice)
|
basis = np.tril(np.random.random((3,3))+1e-6)
|
||||||
R_2 = Orientation(Rotation.from_Eulers([360,0,0],degrees=True),lattice)
|
basis[1,:2] = basis[1,1]*np.array([np.cos(gamma),np.sin(gamma)])
|
||||||
assert np.allclose(R_1.disorientation(R_2).as_matrix(),np.eye(3))
|
basis[2,:2] = basis[2,:2]*2-1
|
||||||
|
lengths = np.linalg.norm(basis,axis=-1)
|
||||||
|
cosines = np.roll(np.einsum('ij,ij->i',basis,np.roll(basis,1,axis=0))/lengths/np.roll(lengths,1),1)
|
||||||
|
o = Orientation.from_random(lattice='aP',
|
||||||
|
**dict(zip(['a','b','c'],lengths)),
|
||||||
|
**dict(zip(['alpha','beta','gamma'],np.arccos(cosines))),
|
||||||
|
)
|
||||||
|
assert np.allclose(o.to_frame(uvw=np.eye(3)),basis), 'Lattice basis disagrees with initialization'
|
||||||
|
|
||||||
@pytest.mark.parametrize('lattice',Lattice.lattices)
|
@pytest.mark.parametrize('lattice,a,b,c,alpha,beta,gamma',
|
||||||
@pytest.mark.parametrize('angle',[10,20,30,40])
|
[
|
||||||
def test_average(self,angle,lattice):
|
('aP',0.5,2.0,3.0,0.8,0.5,1.2),
|
||||||
R_1 = Orientation(Rotation.from_axis_angle([0,0,1,10],degrees=True),lattice)
|
('mP',1.0,2.0,3.0,np.pi/2,0.5,np.pi/2),
|
||||||
R_2 = Orientation(Rotation.from_axis_angle([0,0,1,angle],degrees=True),lattice)
|
('oI',0.5,1.5,3.0,np.pi/2,np.pi/2,np.pi/2),
|
||||||
avg_angle = R_1.average(R_2).rotation.as_axis_angle(degrees=True,pair=True)[1]
|
('tP',0.5,0.5,3.0,np.pi/2,np.pi/2,np.pi/2),
|
||||||
assert np.isclose(avg_angle,10+(angle-10)/2.)
|
('hP',1.0,None,1.6,np.pi/2,np.pi/2,2*np.pi/3),
|
||||||
|
('cF',1.0,1.0,None,np.pi/2,np.pi/2,np.pi/2),
|
||||||
|
])
|
||||||
|
def test_bases_contraction(self,lattice,a,b,c,alpha,beta,gamma):
|
||||||
|
L = Orientation(lattice=lattice,
|
||||||
|
a=a,b=b,c=c,
|
||||||
|
alpha=alpha,beta=beta,gamma=gamma)
|
||||||
|
assert np.allclose(np.eye(3),np.einsum('ik,jk',L.basis_real,L.basis_reciprocal))
|
||||||
|
|
||||||
@pytest.mark.parametrize('lattice',Lattice.lattices)
|
@pytest.mark.parametrize('keyFrame,keyLattice',[('uvw','direction'),('hkl','plane'),])
|
||||||
def test_from_average(self,lattice):
|
@pytest.mark.parametrize('vector',np.array([
|
||||||
R_1 = Orientation(Rotation.from_random(),lattice)
|
[1.,1.,1.],
|
||||||
eqs = [r for r in R_1.equivalent]
|
[-2.,3.,0.5],
|
||||||
R_2 = Orientation.from_average(eqs)
|
[0.,0.,1.],
|
||||||
assert np.allclose(R_1.rotation.quaternion,R_2.rotation.quaternion)
|
[1.,1.,1.],
|
||||||
|
[2.,2.,2.],
|
||||||
|
[0.,1.,1.],
|
||||||
|
]))
|
||||||
|
@pytest.mark.parametrize('lattice,a,b,c,alpha,beta,gamma',
|
||||||
|
[
|
||||||
|
('aP',0.5,2.0,3.0,0.8,0.5,1.2),
|
||||||
|
('mP',1.0,2.0,3.0,np.pi/2,0.5,np.pi/2),
|
||||||
|
('oI',0.5,1.5,3.0,np.pi/2,np.pi/2,np.pi/2),
|
||||||
|
('tP',0.5,0.5,3.0,np.pi/2,np.pi/2,np.pi/2),
|
||||||
|
('hP',1.0,1.0,1.6,np.pi/2,np.pi/2,2*np.pi/3),
|
||||||
|
('cF',1.0,1.0,1.0,np.pi/2,np.pi/2,np.pi/2),
|
||||||
|
])
|
||||||
|
def test_to_frame_to_lattice(self,lattice,a,b,c,alpha,beta,gamma,vector,keyFrame,keyLattice):
|
||||||
|
L = Orientation(lattice=lattice,
|
||||||
|
a=a,b=b,c=c,
|
||||||
|
alpha=alpha,beta=beta,gamma=gamma)
|
||||||
|
assert np.allclose(vector,
|
||||||
|
L.to_frame(**{keyFrame:L.to_lattice(**{keyLattice:vector})}))
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('vector',np.array([
|
||||||
|
[1,0,0],
|
||||||
|
[1,1,0],
|
||||||
|
[1,1,1],
|
||||||
|
[1,0,-2],
|
||||||
|
]))
|
||||||
|
@pytest.mark.parametrize('kw_Miller,kw_Bravais',[('uvw','uvtw'),('hkl','hkil')])
|
||||||
|
def test_Miller_Bravais_Miller(self,vector,kw_Miller,kw_Bravais):
|
||||||
|
assert np.all(vector == Orientation.Bravais_to_Miller(**{kw_Bravais:Orientation.Miller_to_Bravais(**{kw_Miller:vector})}))
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('vector',np.array([
|
||||||
|
[1,0,-1,2],
|
||||||
|
[1,-1,0,3],
|
||||||
|
[1,1,-2,-3],
|
||||||
|
[0,0,0,1],
|
||||||
|
]))
|
||||||
|
@pytest.mark.parametrize('kw_Miller,kw_Bravais',[('uvw','uvtw'),('hkl','hkil')])
|
||||||
|
def test_Bravais_Miller_Bravais(self,vector,kw_Miller,kw_Bravais):
|
||||||
|
assert np.all(vector == Orientation.Miller_to_Bravais(**{kw_Miller:Orientation.Bravais_to_Miller(**{kw_Bravais:vector})}))
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('lattice,a,b,c,alpha,beta,gamma',
|
||||||
|
[
|
||||||
|
('aP',0.5,2.0,3.0,0.8,0.5,1.2),
|
||||||
|
('mP',1.0,2.0,3.0,np.pi/2,0.5,np.pi/2),
|
||||||
|
('oI',0.5,1.5,3.0,np.pi/2,np.pi/2,np.pi/2),
|
||||||
|
('tP',0.5,0.5,3.0,np.pi/2,np.pi/2,np.pi/2),
|
||||||
|
('hP',1.0,1.0,1.6,np.pi/2,np.pi/2,2*np.pi/3),
|
||||||
|
('cF',1.0,1.0,1.0,np.pi/2,np.pi/2,np.pi/2),
|
||||||
|
])
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('kw',['uvw','hkl'])
|
||||||
|
@pytest.mark.parametrize('with_symmetry',[False,True])
|
||||||
|
@pytest.mark.parametrize('shape',[None,1,(12,24)])
|
||||||
|
@pytest.mark.parametrize('vector',[
|
||||||
|
np.random.random( 3 ),
|
||||||
|
np.random.random( (4,3)),
|
||||||
|
np.random.random((4,8,3)),
|
||||||
|
])
|
||||||
|
def test_to_pole(self,shape,lattice,a,b,c,alpha,beta,gamma,vector,kw,with_symmetry):
|
||||||
|
o = Orientation.from_random(shape=shape,
|
||||||
|
lattice=lattice,
|
||||||
|
a=a,b=b,c=c,
|
||||||
|
alpha=alpha,beta=beta,gamma=gamma)
|
||||||
|
assert o.to_pole(**{kw:vector,'with_symmetry':with_symmetry}).shape \
|
||||||
|
== o.shape + (o.symmetry_operations.shape if with_symmetry else ()) + vector.shape
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('lattice',['hP','cI','cF'])
|
||||||
|
def test_Schmid(self,update,reference_dir,lattice):
|
||||||
|
L = Orientation(lattice=lattice)
|
||||||
|
for mode in L.kinematics:
|
||||||
|
reference = reference_dir/f'{lattice}_{mode}.txt'
|
||||||
|
P = L.Schmid(mode)
|
||||||
|
if update:
|
||||||
|
table = Table(P.reshape(-1,9),{'Schmid':(3,3,)})
|
||||||
|
table.save(reference)
|
||||||
|
assert np.allclose(P,Table.load(reference).get('Schmid'))
|
||||||
|
|
|
@ -168,15 +168,16 @@ class TestResult:
|
||||||
|
|
||||||
@pytest.mark.parametrize('d',[[1,0,0],[0,1,0],[0,0,1]])
|
@pytest.mark.parametrize('d',[[1,0,0],[0,1,0],[0,0,1]])
|
||||||
def test_add_IPF_color(self,default,d):
|
def test_add_IPF_color(self,default,d):
|
||||||
default.add_IPF_color('O',d)
|
default.add_IPF_color('O',np.array(d))
|
||||||
loc = {'orientation': default.get_dataset_location('O'),
|
loc = {'O': default.get_dataset_location('O'),
|
||||||
'color': default.get_dataset_location('IPFcolor_[{} {} {}]'.format(*d))}
|
'color': default.get_dataset_location('IPFcolor_[{} {} {}]'.format(*d))}
|
||||||
qu = default.read_dataset(loc['orientation']).view(np.double).reshape(-1,4)
|
qu = default.read_dataset(loc['O']).view(np.double).squeeze()
|
||||||
crystal_structure = default.get_crystal_structure()
|
crystal_structure = default.get_crystal_structure()
|
||||||
in_memory = np.empty((qu.shape[0],3),np.uint8)
|
c = Orientation(rotation=qu,
|
||||||
for i,q in enumerate(qu):
|
lattice={'fcc':'cF',
|
||||||
o = Orientation(q,crystal_structure).reduced
|
'bcc':'cI',
|
||||||
in_memory[i] = np.uint8(o.IPF_color(np.array(d))*255)
|
'hex':'hP'}[crystal_structure])
|
||||||
|
in_memory = np.uint8(c.IPF_color(c.to_SST(np.array(d)))*255)
|
||||||
in_file = default.read_dataset(loc['color'])
|
in_file = default.read_dataset(loc['color'])
|
||||||
assert np.allclose(in_memory,in_file)
|
assert np.allclose(in_memory,in_file)
|
||||||
|
|
||||||
|
@ -244,13 +245,14 @@ class TestResult:
|
||||||
in_file = default.read_dataset(loc['S'],0)
|
in_file = default.read_dataset(loc['S'],0)
|
||||||
assert np.allclose(in_memory,in_file)
|
assert np.allclose(in_memory,in_file)
|
||||||
|
|
||||||
|
@pytest.mark.skip(reason='requires rework of lattice.f90')
|
||||||
@pytest.mark.parametrize('polar',[True,False])
|
@pytest.mark.parametrize('polar',[True,False])
|
||||||
def test_add_pole(self,default,polar):
|
def test_add_pole(self,default,polar):
|
||||||
pole = np.array([1.,0.,0.])
|
pole = np.array([1.,0.,0.])
|
||||||
default.add_pole('O',pole,polar)
|
default.add_pole('O',pole,polar)
|
||||||
loc = {'orientation': default.get_dataset_location('O'),
|
loc = {'O': default.get_dataset_location('O'),
|
||||||
'pole': default.get_dataset_location('p^{}_[1 0 0)'.format(u'rφ' if polar else 'xy'))}
|
'pole': default.get_dataset_location('p^{}_[1 0 0)'.format(u'rφ' if polar else 'xy'))}
|
||||||
rot = Rotation(default.read_dataset(loc['orientation']).view(np.double))
|
rot = Rotation(default.read_dataset(loc['O']).view(np.double))
|
||||||
rotated_pole = rot * np.broadcast_to(pole,rot.shape+(3,))
|
rotated_pole = rot * np.broadcast_to(pole,rot.shape+(3,))
|
||||||
xy = rotated_pole[:,0:2]/(1.+abs(pole[2]))
|
xy = rotated_pole[:,0:2]/(1.+abs(pole[2]))
|
||||||
in_memory = xy if not polar else \
|
in_memory = xy if not polar else \
|
||||||
|
|
|
@ -771,6 +771,53 @@ class TestRotation:
|
||||||
def test_random(self,shape):
|
def test_random(self,shape):
|
||||||
Rotation.from_random(shape)
|
Rotation.from_random(shape)
|
||||||
|
|
||||||
|
def test_equal(self):
|
||||||
|
r = Rotation.from_random(seed=0)
|
||||||
|
assert r == r
|
||||||
|
|
||||||
|
def test_unequal(self):
|
||||||
|
r = Rotation.from_random(seed=0)
|
||||||
|
assert not (r != r)
|
||||||
|
|
||||||
|
def test_inversion(self):
|
||||||
|
r = Rotation.from_random(seed=0)
|
||||||
|
assert r == ~~r
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('shape',[None,1,(1,),(4,2),(1,1,1)])
|
||||||
|
def test_shape(self,shape):
|
||||||
|
r = Rotation.from_random(shape=shape)
|
||||||
|
assert r.shape == (shape if isinstance(shape,tuple) else (shape,) if shape else ())
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('shape',[None,1,(1,),(4,2),(3,3,2)])
|
||||||
|
def test_append(self,shape):
|
||||||
|
r = Rotation.from_random(shape=shape)
|
||||||
|
p = Rotation.from_random(shape=shape)
|
||||||
|
s = r.append(p)
|
||||||
|
print(f'append 2x {shape} --> {s.shape}')
|
||||||
|
assert s[0,...] == r[0,...] and s[-1,...] == p[-1,...]
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('quat,standardized',[
|
||||||
|
([-1,0,0,0],[1,0,0,0]),
|
||||||
|
([-0.5,-0.5,-0.5,-0.5],[0.5,0.5,0.5,0.5]),
|
||||||
|
])
|
||||||
|
def test_standardization(self,quat,standardized):
|
||||||
|
assert Rotation(quat)._standardize() == Rotation(standardized)
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('shape,length',[
|
||||||
|
((2,3,4),2),
|
||||||
|
(4,4),
|
||||||
|
((),0)
|
||||||
|
])
|
||||||
|
def test_len(self,shape,length):
|
||||||
|
r = Rotation.from_random(shape=shape)
|
||||||
|
assert len(r) == length
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('shape',[(4,6),(2,3,4),(3,3,3)])
|
||||||
|
@pytest.mark.parametrize('order',['C','F'])
|
||||||
|
def test_flatten_reshape(self,shape,order):
|
||||||
|
r = Rotation.from_random(shape=shape)
|
||||||
|
assert r == r.flatten(order).reshape(shape,order)
|
||||||
|
|
||||||
@pytest.mark.parametrize('function',[Rotation.from_quaternion,
|
@pytest.mark.parametrize('function',[Rotation.from_quaternion,
|
||||||
Rotation.from_Eulers,
|
Rotation.from_Eulers,
|
||||||
Rotation.from_axis_angle,
|
Rotation.from_axis_angle,
|
||||||
|
@ -848,7 +895,8 @@ class TestRotation:
|
||||||
np.random.rand(3,3,3,3)])
|
np.random.rand(3,3,3,3)])
|
||||||
def test_rotate_identity(self,data):
|
def test_rotate_identity(self,data):
|
||||||
R = Rotation()
|
R = Rotation()
|
||||||
assert np.allclose(data,R*data)
|
print(R,data)
|
||||||
|
assert np.allclose(data,R@data)
|
||||||
|
|
||||||
@pytest.mark.parametrize('data',[np.random.rand(3),
|
@pytest.mark.parametrize('data',[np.random.rand(3),
|
||||||
np.random.rand(3,3),
|
np.random.rand(3,3),
|
||||||
|
@ -860,6 +908,16 @@ class TestRotation:
|
||||||
R_2 = Rotation.from_Eulers(np.array([0.,0.,phi_2]))
|
R_2 = Rotation.from_Eulers(np.array([0.,0.,phi_2]))
|
||||||
assert np.allclose(data,R_2@(R_1@data))
|
assert np.allclose(data,R_2@(R_1@data))
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('pwr',[-10,0,1,2.5,np.pi,np.random.random()])
|
||||||
|
def test_rotate_power(self,pwr):
|
||||||
|
R = Rotation.from_random()
|
||||||
|
axis_angle = R.as_axis_angle()
|
||||||
|
axis_angle[ 3] = (pwr*axis_angle[-1])%(2.*np.pi)
|
||||||
|
if axis_angle[3] > np.pi:
|
||||||
|
axis_angle[3] -= 2.*np.pi
|
||||||
|
axis_angle *= -1
|
||||||
|
assert R**pwr == Rotation.from_axis_angle(axis_angle)
|
||||||
|
|
||||||
def test_rotate_inverse(self):
|
def test_rotate_inverse(self):
|
||||||
R = Rotation.from_random()
|
R = Rotation.from_random()
|
||||||
assert np.allclose(np.eye(3),(~R@R).as_matrix())
|
assert np.allclose(np.eye(3),(~R@R).as_matrix())
|
||||||
|
@ -877,7 +935,7 @@ class TestRotation:
|
||||||
def test_rotate_invalid_shape(self,data):
|
def test_rotate_invalid_shape(self,data):
|
||||||
R = Rotation.from_random()
|
R = Rotation.from_random()
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
R*data
|
R@data
|
||||||
|
|
||||||
@pytest.mark.parametrize('data',['does_not_work',
|
@pytest.mark.parametrize('data',['does_not_work',
|
||||||
(1,2),
|
(1,2),
|
||||||
|
@ -885,7 +943,7 @@ class TestRotation:
|
||||||
def test_rotate_invalid_type(self,data):
|
def test_rotate_invalid_type(self,data):
|
||||||
R = Rotation.from_random()
|
R = Rotation.from_random()
|
||||||
with pytest.raises(TypeError):
|
with pytest.raises(TypeError):
|
||||||
R*data
|
R@data
|
||||||
|
|
||||||
def test_misorientation(self):
|
def test_misorientation(self):
|
||||||
R = Rotation.from_random()
|
R = Rotation.from_random()
|
||||||
|
@ -898,9 +956,8 @@ class TestRotation:
|
||||||
|
|
||||||
@pytest.mark.parametrize('angle',[10,20,30,40,50,60,70,80,90,100,120])
|
@pytest.mark.parametrize('angle',[10,20,30,40,50,60,70,80,90,100,120])
|
||||||
def test_average(self,angle):
|
def test_average(self,angle):
|
||||||
R_1 = Rotation.from_axis_angle([0,0,1,10],degrees=True)
|
R = Rotation.from_axis_angle([[0,0,1,10],[0,0,1,angle]],degrees=True)
|
||||||
R_2 = Rotation.from_axis_angle([0,0,1,angle],degrees=True)
|
avg_angle = R.average().as_axis_angle(degrees=True,pair=True)[1]
|
||||||
avg_angle = R_1.average(R_2).as_axis_angle(degrees=True,pair=True)[1]
|
|
||||||
assert np.isclose(avg_angle,10+(angle-10)/2.)
|
assert np.isclose(avg_angle,10+(angle-10)/2.)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -44,3 +44,52 @@ class TestUtil:
|
||||||
selected = util.hybrid_IA(dist,N_samples)
|
selected = util.hybrid_IA(dist,N_samples)
|
||||||
dist_sampled = np.histogram(centers[selected],bins)[0]/N_samples*np.sum(dist)
|
dist_sampled = np.histogram(centers[selected],bins)[0]/N_samples*np.sum(dist)
|
||||||
assert np.sqrt(((dist - dist_sampled) ** 2).mean()) < .025 and selected.shape[0]==N_samples
|
assert np.sqrt(((dist - dist_sampled) ** 2).mean()) < .025 and selected.shape[0]==N_samples
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('point,normalize,answer',
|
||||||
|
[
|
||||||
|
([1,0,0],False,[1,0,0]),
|
||||||
|
([1,0,0],True, [1,0,0]),
|
||||||
|
([0,1,1],False,[0,0.5,0]),
|
||||||
|
([0,1,1],True, [0,0.41421356,0]),
|
||||||
|
([1,1,1],False,[0.5,0.5,0]),
|
||||||
|
([1,1,1],True, [0.3660254, 0.3660254, 0]),
|
||||||
|
])
|
||||||
|
def test_project_stereographic(self,point,normalize,answer):
|
||||||
|
assert np.allclose(util.project_stereographic(np.array(point),normalize=normalize),answer)
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('fro,to,mode,answer',
|
||||||
|
[
|
||||||
|
((),(1,),'left',(1,)),
|
||||||
|
((1,),(7,),'right',(1,)),
|
||||||
|
((1,2),(1,1,2,2),'right',(1,1,2,1)),
|
||||||
|
((1,2),(1,1,2,2),'left',(1,1,1,2)),
|
||||||
|
((1,2,3),(1,1,2,3,4),'right',(1,1,2,3,1)),
|
||||||
|
((10,2),(10,3,2,2,),'right',(10,1,2,1)),
|
||||||
|
((10,2),(10,3,2,2,),'left',(10,1,1,2)),
|
||||||
|
((2,2,3),(2,2,2,3,4),'left',(1,2,2,3,1)),
|
||||||
|
((2,2,3),(2,2,2,3,4),'right',(2,2,1,3,1)),
|
||||||
|
])
|
||||||
|
def test_shapeshifter(self,fro,to,mode,answer):
|
||||||
|
assert util.shapeshifter(fro,to,mode) == answer
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('fro,to,mode',
|
||||||
|
[
|
||||||
|
((10,3,4),(10,3,2,2),'left'),
|
||||||
|
((2,3),(10,3,2,2),'right'),
|
||||||
|
])
|
||||||
|
def test_invalid_shapeshifter(self,fro,to,mode):
|
||||||
|
with pytest.raises(ValueError):
|
||||||
|
util.shapeshifter(fro,to,mode)
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('a,b,answer',
|
||||||
|
[
|
||||||
|
((),(1,),(1,)),
|
||||||
|
((1,),(),(1,)),
|
||||||
|
((1,),(7,),(1,7)),
|
||||||
|
((2,),(2,2),(2,2)),
|
||||||
|
((1,2),(2,2),(1,2,2)),
|
||||||
|
((1,2,3),(2,3,4),(1,2,3,4)),
|
||||||
|
((1,2,3),(1,2,3),(1,2,3)),
|
||||||
|
])
|
||||||
|
def test_shapeblender(self,a,b,answer):
|
||||||
|
assert util.shapeblender(a,b) == answer
|
||||||
|
|
|
@ -93,7 +93,8 @@ subroutine prec_init
|
||||||
print'(a,i19)', ' Maximum value: ',huge(0)
|
print'(a,i19)', ' Maximum value: ',huge(0)
|
||||||
print'(/,a,i3)', ' Size of float in bit: ',storage_size(0.0_pReal)
|
print'(/,a,i3)', ' Size of float in bit: ',storage_size(0.0_pReal)
|
||||||
print'(a,e10.3)', ' Maximum value: ',huge(0.0_pReal)
|
print'(a,e10.3)', ' Maximum value: ',huge(0.0_pReal)
|
||||||
print'(a,e10.3)', ' Minimum value: ',tiny(0.0_pReal)
|
print'(a,e10.3)', ' Minimum value: ',PREAL_MIN
|
||||||
|
print'(a,e10.3)', ' Epsilon value: ',PREAL_EPSILON
|
||||||
print'(a,i3)', ' Decimal precision: ',precision(0.0_pReal)
|
print'(a,i3)', ' Decimal precision: ',precision(0.0_pReal)
|
||||||
|
|
||||||
call selfTest
|
call selfTest
|
||||||
|
|
Loading…
Reference in New Issue