Merge branch 'improved-docstrings' into 'development'
Improvements to Python docstrings See merge request damask/DAMASK!729
This commit is contained in:
commit
538770278f
|
@ -28,10 +28,10 @@ _REF_WHITE = np.array([.95047, 1.00000, 1.08883])
|
||||||
|
|
||||||
class Colormap(mpl.colors.ListedColormap):
|
class Colormap(mpl.colors.ListedColormap):
|
||||||
"""
|
"""
|
||||||
Enhance matplotlib colormap functionality to be used within DAMASK.
|
Enhance matplotlib colormap functionality for use within DAMASK.
|
||||||
|
|
||||||
Colors are internally stored as R(ed) G(green) B(lue) values.
|
Colors are internally stored as R(ed) G(green) B(lue) values.
|
||||||
The colormap can be used in matplotlib, seaborn, etc., or can
|
A colormap can be used in matplotlib, seaborn, etc., or can be
|
||||||
exported to file for external use.
|
exported to file for external use.
|
||||||
|
|
||||||
References
|
References
|
||||||
|
@ -153,12 +153,12 @@ class Colormap(mpl.colors.ListedColormap):
|
||||||
- 'hsl': Hue Saturation Luminance.
|
- 'hsl': Hue Saturation Luminance.
|
||||||
- 'xyz': CIE Xyz.
|
- 'xyz': CIE Xyz.
|
||||||
- 'lab': CIE Lab.
|
- 'lab': CIE Lab.
|
||||||
- 'msh': Msh (for perceptual uniform interpolation).
|
- 'msh': Msh (for perceptually uniform interpolation).
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
-------
|
-------
|
||||||
new : damask.Colormap
|
new : damask.Colormap
|
||||||
Colormap within given bounds.
|
Colormap spanning given bounds.
|
||||||
|
|
||||||
Examples
|
Examples
|
||||||
--------
|
--------
|
||||||
|
@ -288,6 +288,7 @@ class Colormap(mpl.colors.ListedColormap):
|
||||||
Value range (left,right) spanned by colormap.
|
Value range (left,right) spanned by colormap.
|
||||||
gap : field.dtype, optional
|
gap : field.dtype, optional
|
||||||
Transparent value. NaN will always be rendered transparent.
|
Transparent value. NaN will always be rendered transparent.
|
||||||
|
Defaults to None.
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
-------
|
-------
|
||||||
|
@ -334,6 +335,7 @@ class Colormap(mpl.colors.ListedColormap):
|
||||||
--------
|
--------
|
||||||
>>> import damask
|
>>> import damask
|
||||||
>>> damask.Colormap.from_predefined('stress').reversed()
|
>>> damask.Colormap.from_predefined('stress').reversed()
|
||||||
|
Colormap: stress_r
|
||||||
|
|
||||||
"""
|
"""
|
||||||
rev = super().reversed(name)
|
rev = super().reversed(name)
|
||||||
|
@ -353,6 +355,7 @@ class Colormap(mpl.colors.ListedColormap):
|
||||||
If None, colormap name + suffix.
|
If None, colormap name + suffix.
|
||||||
suffix: str, optional
|
suffix: str, optional
|
||||||
Extension to use for colormap file.
|
Extension to use for colormap file.
|
||||||
|
Defaults to empty.
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
-------
|
-------
|
||||||
|
@ -452,8 +455,8 @@ class Colormap(mpl.colors.ListedColormap):
|
||||||
|
|
||||||
References
|
References
|
||||||
----------
|
----------
|
||||||
https://www.kennethmoreland.com/color-maps/ColorMapsExpanded.pdf
|
| https://www.kennethmoreland.com/color-maps/ColorMapsExpanded.pdf
|
||||||
https://www.kennethmoreland.com/color-maps/diverging_map.py
|
| https://www.kennethmoreland.com/color-maps/diverging_map.py
|
||||||
|
|
||||||
"""
|
"""
|
||||||
def rad_diff(a,b):
|
def rad_diff(a,b):
|
||||||
|
@ -735,8 +738,8 @@ class Colormap(mpl.colors.ListedColormap):
|
||||||
|
|
||||||
References
|
References
|
||||||
----------
|
----------
|
||||||
https://www.kennethmoreland.com/color-maps/ColorMapsExpanded.pdf
|
| https://www.kennethmoreland.com/color-maps/ColorMapsExpanded.pdf
|
||||||
https://www.kennethmoreland.com/color-maps/diverging_map.py
|
| https://www.kennethmoreland.com/color-maps/diverging_map.py
|
||||||
|
|
||||||
"""
|
"""
|
||||||
M = np.linalg.norm(lab)
|
M = np.linalg.norm(lab)
|
||||||
|
@ -763,8 +766,8 @@ class Colormap(mpl.colors.ListedColormap):
|
||||||
|
|
||||||
References
|
References
|
||||||
----------
|
----------
|
||||||
https://www.kennethmoreland.com/color-maps/ColorMapsExpanded.pdf
|
| https://www.kennethmoreland.com/color-maps/ColorMapsExpanded.pdf
|
||||||
https://www.kennethmoreland.com/color-maps/diverging_map.py
|
| https://www.kennethmoreland.com/color-maps/diverging_map.py
|
||||||
|
|
||||||
"""
|
"""
|
||||||
return np.array([
|
return np.array([
|
||||||
|
|
|
@ -307,15 +307,13 @@ class Crystal():
|
||||||
Cubic crystal family:
|
Cubic crystal family:
|
||||||
|
|
||||||
>>> import damask
|
>>> import damask
|
||||||
>>> cubic = damask.Crystal(family='cubic')
|
>>> (cubic := damask.Crystal(family='cubic'))
|
||||||
>>> cubic
|
|
||||||
Crystal family: cubic
|
Crystal family: cubic
|
||||||
|
|
||||||
Body-centered cubic Bravais lattice with parameters of iron:
|
Body-centered cubic Bravais lattice with parameters of iron:
|
||||||
|
|
||||||
>>> import damask
|
>>> import damask
|
||||||
>>> Fe = damask.Crystal(lattice='cI', a=287e-12)
|
>>> (Fe := damask.Crystal(lattice='cI', a=287e-12))
|
||||||
>>> Fe
|
|
||||||
Crystal family: cubic
|
Crystal family: cubic
|
||||||
Bravais lattice: cI
|
Bravais lattice: cI
|
||||||
a=2.87e-10 m, b=2.87e-10 m, c=2.87e-10 m
|
a=2.87e-10 m, b=2.87e-10 m, c=2.87e-10 m
|
||||||
|
@ -406,7 +404,7 @@ class Crystal():
|
||||||
"""
|
"""
|
||||||
Return repr(self).
|
Return repr(self).
|
||||||
|
|
||||||
Give short human-readable summary.
|
Give short, human-readable summary.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
family = f'Crystal family: {self.family}'
|
family = f'Crystal family: {self.family}'
|
||||||
|
|
|
@ -32,10 +32,10 @@ class Grid:
|
||||||
"""
|
"""
|
||||||
Geometry definition for grid solvers.
|
Geometry definition for grid solvers.
|
||||||
|
|
||||||
Create and manipulate geometry definitions for storage as VTK
|
Create and manipulate geometry definitions for storage as VTK ImageData
|
||||||
image data files ('.vti' extension). A grid contains the
|
files ('.vti' extension). A grid has a physical size, a coordinate origin,
|
||||||
material ID (referring to the entry in 'material.yaml') and
|
and contains the material ID (indexing an entry in 'material.yaml')
|
||||||
the physical size.
|
as well as initial condition fields.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
|
@ -57,7 +57,7 @@ class Grid:
|
||||||
origin : sequence of float, len (3), optional
|
origin : sequence of float, len (3), optional
|
||||||
Coordinates of grid origin in meter. Defaults to [0.0,0.0,0.0].
|
Coordinates of grid origin in meter. Defaults to [0.0,0.0,0.0].
|
||||||
initial_conditions : dictionary, optional
|
initial_conditions : dictionary, optional
|
||||||
Labels and values of the inital conditions at each material point.
|
Initial condition label and field values at each grid point.
|
||||||
comments : (sequence of) str, optional
|
comments : (sequence of) str, optional
|
||||||
Additional, human-readable information, e.g. history of operations.
|
Additional, human-readable information, e.g. history of operations.
|
||||||
|
|
||||||
|
@ -74,7 +74,7 @@ class Grid:
|
||||||
"""
|
"""
|
||||||
Return repr(self).
|
Return repr(self).
|
||||||
|
|
||||||
Give short human-readable summary.
|
Give short, human-readable summary.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
mat_min = np.nanmin(self.material)
|
mat_min = np.nanmin(self.material)
|
||||||
|
@ -144,7 +144,7 @@ class Grid:
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def size(self) -> np.ndarray:
|
def size(self) -> np.ndarray:
|
||||||
"""Physical size of grid in meter."""
|
"""Edge lengths of grid in meter."""
|
||||||
return self._size
|
return self._size
|
||||||
|
|
||||||
@size.setter
|
@size.setter
|
||||||
|
@ -157,7 +157,7 @@ class Grid:
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def origin(self) -> np.ndarray:
|
def origin(self) -> np.ndarray:
|
||||||
"""Coordinates of grid origin in meter."""
|
"""Vector to grid origin in meter."""
|
||||||
return self._origin
|
return self._origin
|
||||||
|
|
||||||
@origin.setter
|
@origin.setter
|
||||||
|
@ -186,7 +186,7 @@ class Grid:
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def cells(self) -> np.ndarray:
|
def cells(self) -> np.ndarray:
|
||||||
"""Number of cells in x,y,z direction."""
|
"""Cell counts along x,y,z direction."""
|
||||||
return np.asarray(self.material.shape)
|
return np.asarray(self.material.shape)
|
||||||
|
|
||||||
|
|
||||||
|
@ -199,7 +199,7 @@ class Grid:
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def load(fname: Union[str, Path]) -> 'Grid':
|
def load(fname: Union[str, Path]) -> 'Grid':
|
||||||
"""
|
"""
|
||||||
Load from VTK image data file.
|
Load from VTK ImageData file.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
|
@ -470,9 +470,9 @@ class Grid:
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
cells : sequence of int, len (3)
|
cells : sequence of int, len (3)
|
||||||
Number of cells in x,y,z direction.
|
Cell counts along x,y,z direction.
|
||||||
size : sequence of float, len (3)
|
size : sequence of float, len (3)
|
||||||
Physical size of the grid in meter.
|
Edge lengths of the grid in meter.
|
||||||
seeds : numpy.ndarray of float, shape (:,3)
|
seeds : numpy.ndarray of float, 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.
|
||||||
weights : sequence of float, len (seeds.shape[0])
|
weights : sequence of float, len (seeds.shape[0])
|
||||||
|
@ -527,9 +527,9 @@ class Grid:
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
cells : sequence of int, len (3)
|
cells : sequence of int, len (3)
|
||||||
Number of cells in x,y,z direction.
|
Cell counts along x,y,z direction.
|
||||||
size : sequence of float, len (3)
|
size : sequence of float, len (3)
|
||||||
Physical size of the grid in meter.
|
Edge lengths of the grid in meter.
|
||||||
seeds : numpy.ndarray of float, shape (:,3)
|
seeds : numpy.ndarray of float, 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 : sequence of int, len (seeds.shape[0]), optional
|
material : sequence of int, len (seeds.shape[0]), optional
|
||||||
|
@ -608,14 +608,14 @@ class Grid:
|
||||||
periods: int = 1,
|
periods: int = 1,
|
||||||
materials: IntSequence = (0,1)) -> 'Grid':
|
materials: IntSequence = (0,1)) -> 'Grid':
|
||||||
"""
|
"""
|
||||||
Create grid from definition of triply periodic minimal surface.
|
Create grid from definition of triply-periodic minimal surface.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
cells : sequence of int, len (3)
|
cells : sequence of int, len (3)
|
||||||
Number of cells in x,y,z direction.
|
Cell counts along x,y,z direction.
|
||||||
size : sequence of float, len (3)
|
size : sequence of float, len (3)
|
||||||
Physical size of the grid in meter.
|
Edge lengths of the grid in meter.
|
||||||
surface : str
|
surface : str
|
||||||
Type of the minimal surface. See notes for details.
|
Type of the minimal surface. See notes for details.
|
||||||
threshold : float, optional.
|
threshold : float, optional.
|
||||||
|
@ -664,19 +664,19 @@ class Grid:
|
||||||
>>> import numpy as np
|
>>> import numpy as np
|
||||||
>>> import damask
|
>>> import damask
|
||||||
>>> damask.Grid.from_minimal_surface([64]*3,np.ones(3)*1.e-4,'Gyroid')
|
>>> damask.Grid.from_minimal_surface([64]*3,np.ones(3)*1.e-4,'Gyroid')
|
||||||
cells : 64 x 64 x 64
|
cells : 64 × 64 × 64
|
||||||
size : 0.0001 x 0.0001 x 0.0001 m³
|
size : 0.0001 × 0.0001 × 0.0001 m³
|
||||||
origin: 0.0 0.0 0.0 m
|
origin: 0.0 0.0 0.0 m
|
||||||
# materials: 2
|
# materials: 2
|
||||||
|
|
||||||
Minimal surface of 'Neovius' type with non-default material IDs.
|
Minimal surface of 'Neovius' type with specific material IDs.
|
||||||
|
|
||||||
>>> import numpy as np
|
>>> import numpy as np
|
||||||
>>> import damask
|
>>> import damask
|
||||||
>>> damask.Grid.from_minimal_surface([80]*3,np.ones(3)*5.e-4,
|
>>> damask.Grid.from_minimal_surface([80]*3,np.ones(3)*5.e-4,
|
||||||
... 'Neovius',materials=(1,5))
|
... 'Neovius',materials=(1,5))
|
||||||
cells : 80 x 80 x 80
|
cells : 80 × 80 × 80
|
||||||
size : 0.0005 x 0.0005 x 0.0005 m³
|
size : 0.0005 × 0.0005 × 0.0005 m³
|
||||||
origin: 0.0 0.0 0.0 m
|
origin: 0.0 0.0 0.0 m
|
||||||
# materials: 2 (min: 1, max: 5)
|
# materials: 2 (min: 1, max: 5)
|
||||||
|
|
||||||
|
@ -695,12 +695,13 @@ class Grid:
|
||||||
fname: Union[str, Path],
|
fname: Union[str, Path],
|
||||||
compress: bool = True):
|
compress: bool = True):
|
||||||
"""
|
"""
|
||||||
Save as VTK image data file.
|
Save as VTK ImageData file.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
fname : str or pathlib.Path
|
fname : str or pathlib.Path
|
||||||
Filename to write. Valid extension is .vti, it will be appended if not given.
|
Filename to write.
|
||||||
|
Valid extension is .vti, which will be appended if not given.
|
||||||
compress : bool, optional
|
compress : bool, optional
|
||||||
Compress with zlib algorithm. Defaults to True.
|
Compress with zlib algorithm. Defaults to True.
|
||||||
|
|
||||||
|
@ -727,7 +728,7 @@ class Grid:
|
||||||
fname : str or file handle
|
fname : str or file handle
|
||||||
Geometry file to write with extension '.geom'.
|
Geometry file to write with extension '.geom'.
|
||||||
compress : bool, optional
|
compress : bool, optional
|
||||||
Compress geometry with 'x of y' and 'a to b'.
|
Compress geometry using 'x of y' and 'a to b'.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
warnings.warn('Support for ASCII-based geom format will be removed in DAMASK 3.0.0', DeprecationWarning,2)
|
warnings.warn('Support for ASCII-based geom format will be removed in DAMASK 3.0.0', DeprecationWarning,2)
|
||||||
|
@ -771,13 +772,13 @@ class Grid:
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
cells : sequence of int, len (3), optional
|
cells : sequence of int, len (3), optional
|
||||||
Number of cells x,y,z direction.
|
Cell counts along x,y,z direction.
|
||||||
offset : sequence of int, len (3), optional
|
offset : sequence of int, len (3), optional
|
||||||
Offset (measured in cells) from old to new grid.
|
Offset (measured in cells) from old to new grid.
|
||||||
Defaults to [0,0,0].
|
Defaults to [0,0,0].
|
||||||
fill : int, optional
|
fill : int, optional
|
||||||
Material ID to fill the background.
|
Material ID to fill the background.
|
||||||
Defaults to material.max() + 1.
|
Defaults to material.max()+1.
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
-------
|
-------
|
||||||
|
@ -790,11 +791,11 @@ class Grid:
|
||||||
|
|
||||||
>>> import numpy as np
|
>>> import numpy as np
|
||||||
>>> import damask
|
>>> import damask
|
||||||
>>> g = damask.Grid(np.zeros([32]*3,int),np.ones(3)*1e-4)
|
>>> g = damask.Grid(np.zeros([32]*3,int),np.ones(3)*1e-3)
|
||||||
>>> g.canvas([32,32,16],[0,0,16])
|
>>> g.canvas([32,32,16],[0,0,16])
|
||||||
cells : 33 x 32 x 16
|
cells: 32 × 32 × 16
|
||||||
size : 0.0001 x 0.0001 x 5e-05 m³
|
size: 0.001 × 0.001 × 0.0005 m³
|
||||||
origin: 0.0 0.0 5e-05 m
|
origin: 0.0 0.0 0.0005 m
|
||||||
# materials: 1
|
# materials: 1
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
@ -837,16 +838,33 @@ class Grid:
|
||||||
|
|
||||||
Examples
|
Examples
|
||||||
--------
|
--------
|
||||||
Mirror along x- and y-direction.
|
Mirror along y-direction.
|
||||||
|
|
||||||
>>> import numpy as np
|
>>> import numpy as np
|
||||||
>>> import damask
|
>>> import damask
|
||||||
>>> g = damask.Grid(np.zeros([32]*3,int),np.ones(3)*1e-4)
|
>>> (g := damask.Grid(np.arange(4*5*6).reshape([4,5,6]),np.ones(3)))
|
||||||
>>> g.mirror('xy',True)
|
cells: 4 × 5 × 6
|
||||||
cells : 64 x 64 x 32
|
size: 1.0 × 1.0 × 1.0 m³
|
||||||
size : 0.0002 x 0.0002 x 0.0001 m³
|
|
||||||
origin: 0.0 0.0 0.0 m
|
origin: 0.0 0.0 0.0 m
|
||||||
# materials: 1
|
# materials: 120
|
||||||
|
>>> g.mirror('y')
|
||||||
|
cells: 4 × 8 × 6
|
||||||
|
size: 1.0 × 1.6 × 1.0 m³
|
||||||
|
origin: 0.0 0.0 0.0 m
|
||||||
|
# materials: 120
|
||||||
|
|
||||||
|
Reflect along x- and y-direction.
|
||||||
|
|
||||||
|
>>> g.mirror('xy',reflect=True)
|
||||||
|
cells: 8 × 10 × 6
|
||||||
|
size: 2.0 × 2.0 × 1.0 m³
|
||||||
|
origin: 0.0 0.0 0.0 m
|
||||||
|
# materials: 120
|
||||||
|
|
||||||
|
Independence of mirroring order.
|
||||||
|
|
||||||
|
>>> g.mirror('xy') == g.mirror(['y','x'])
|
||||||
|
True
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if not set(directions).issubset(valid := ['x', 'y', 'z']):
|
if not set(directions).issubset(valid := ['x', 'y', 'z']):
|
||||||
|
@ -884,11 +902,29 @@ class Grid:
|
||||||
updated : damask.Grid
|
updated : damask.Grid
|
||||||
Updated grid-based geometry.
|
Updated grid-based geometry.
|
||||||
|
|
||||||
|
Examples
|
||||||
|
--------
|
||||||
|
Invariance of flipping order.
|
||||||
|
|
||||||
|
>>> import numpy as np
|
||||||
|
>>> import damask
|
||||||
|
>>> (g := damask.Grid(np.arange(4*5*6).reshape([4,5,6]),np.ones(3)))
|
||||||
|
cells: 4 × 5 × 6
|
||||||
|
size: 1.0 × 1.0 × 1.0 m³
|
||||||
|
origin: 0.0 0.0 0.0 m
|
||||||
|
# materials: 120
|
||||||
|
>>> g.flip('xyz') == g.flip(['x','z','y'])
|
||||||
|
True
|
||||||
|
|
||||||
|
Invariance of flipping a (fully) mirrored grid.
|
||||||
|
|
||||||
|
>>> g.mirror('x',True) == g.mirror('x',True).flip('x')
|
||||||
|
True
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if not set(directions).issubset(valid := ['x', 'y', 'z']):
|
if not set(directions).issubset(valid := ['x', 'y', 'z']):
|
||||||
raise ValueError(f'invalid direction "{set(directions).difference(valid)}" specified')
|
raise ValueError(f'invalid direction "{set(directions).difference(valid)}" specified')
|
||||||
|
|
||||||
|
|
||||||
mat = np.flip(self.material, [valid.index(d) for d in directions if d in valid])
|
mat = np.flip(self.material, [valid.index(d) for d in directions if d in valid])
|
||||||
|
|
||||||
return Grid(material = mat,
|
return Grid(material = mat,
|
||||||
|
@ -902,7 +938,7 @@ class Grid:
|
||||||
R: Rotation,
|
R: Rotation,
|
||||||
fill: Optional[int] = None) -> 'Grid':
|
fill: Optional[int] = None) -> 'Grid':
|
||||||
"""
|
"""
|
||||||
Rotate grid (and pad if required).
|
Rotate grid (possibly extending its bounding box).
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
|
@ -910,13 +946,27 @@ class Grid:
|
||||||
Rotation to apply to the grid.
|
Rotation to apply to the grid.
|
||||||
fill : int, optional
|
fill : int, optional
|
||||||
Material ID to fill enlarged bounding box.
|
Material ID to fill enlarged bounding box.
|
||||||
Defaults to material.max() + 1.
|
Defaults to material.max()+1.
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
-------
|
-------
|
||||||
updated : damask.Grid
|
updated : damask.Grid
|
||||||
Updated grid-based geometry.
|
Updated grid-based geometry.
|
||||||
|
|
||||||
|
Examples
|
||||||
|
--------
|
||||||
|
Rotation by 180° (π) is equivalent to twice flipping.
|
||||||
|
|
||||||
|
>>> import numpy as np
|
||||||
|
>>> import damask
|
||||||
|
>>> (g := damask.Grid(np.arange(4*5*6).reshape([4,5,6]),np.ones(3)))
|
||||||
|
cells: 4 × 5 × 6
|
||||||
|
size: 1.0 × 1.0 × 1.0 m³
|
||||||
|
origin: 0.0 0.0 0.0 m
|
||||||
|
# materials: 120
|
||||||
|
>>> g.rotate(damask.Rotation.from_axis_angle([0,0,1,180],degrees=True)) == g.flip('xy')
|
||||||
|
True
|
||||||
|
|
||||||
"""
|
"""
|
||||||
material = self.material
|
material = self.material
|
||||||
# These rotations are always applied in the reference coordinate system, i.e. (z,x,z) not (z,x',z'')
|
# These rotations are always applied in the reference coordinate system, i.e. (z,x,z) not (z,x',z'')
|
||||||
|
@ -941,12 +991,12 @@ class Grid:
|
||||||
def scale(self,
|
def scale(self,
|
||||||
cells: IntSequence) -> 'Grid':
|
cells: IntSequence) -> 'Grid':
|
||||||
"""
|
"""
|
||||||
Scale grid to new cell count.
|
Scale grid to new cell counts.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
cells : sequence of int, len (3)
|
cells : sequence of int, len (3)
|
||||||
Number of cells in x,y,z direction.
|
Cell counts along x,y,z direction.
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
-------
|
-------
|
||||||
|
@ -955,7 +1005,7 @@ class Grid:
|
||||||
|
|
||||||
Examples
|
Examples
|
||||||
--------
|
--------
|
||||||
Double resolution.
|
Double grid resolution.
|
||||||
|
|
||||||
>>> import numpy as np
|
>>> import numpy as np
|
||||||
>>> import damask
|
>>> import damask
|
||||||
|
@ -965,8 +1015,8 @@ class Grid:
|
||||||
origin: 0.0 0.0 0.0 m
|
origin: 0.0 0.0 0.0 m
|
||||||
# materials: 1
|
# materials: 1
|
||||||
>>> g.scale(g.cells*2)
|
>>> g.scale(g.cells*2)
|
||||||
cells : 64 x 64 x 64
|
cells : 64 × 64 × 64
|
||||||
size : 0.0001 x 0.0001 x 0.0001 m³
|
size : 0.0001 × 0.0001 × 0.0001 m³
|
||||||
origin: 0.0 0.0 0.0 m
|
origin: 0.0 0.0 0.0 m
|
||||||
# materials: 1
|
# materials: 1
|
||||||
|
|
||||||
|
@ -1069,7 +1119,7 @@ class Grid:
|
||||||
|
|
||||||
def sort(self) -> 'Grid':
|
def sort(self) -> 'Grid':
|
||||||
"""
|
"""
|
||||||
Sort material indices such that min(material) is located at (0,0,0).
|
Sort material indices such that min(material ID) is located at (0,0,0).
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
-------
|
-------
|
||||||
|
@ -1186,7 +1236,7 @@ class Grid:
|
||||||
fill : int, optional
|
fill : int, optional
|
||||||
Fill value for primitive. Defaults to material.max()+1.
|
Fill value for primitive. Defaults to material.max()+1.
|
||||||
R : damask.Rotation, optional
|
R : damask.Rotation, optional
|
||||||
Rotation of primitive. Defaults to no rotation.
|
Rotation of the primitive. Defaults to no rotation.
|
||||||
inverse : bool, optional
|
inverse : bool, optional
|
||||||
Retain original materials within primitive and fill outside.
|
Retain original materials within primitive and fill outside.
|
||||||
Defaults to False.
|
Defaults to False.
|
||||||
|
@ -1206,8 +1256,8 @@ class Grid:
|
||||||
>>> import damask
|
>>> import damask
|
||||||
>>> g = damask.Grid(np.zeros([64]*3,int), np.ones(3)*1e-4)
|
>>> g = damask.Grid(np.zeros([64]*3,int), np.ones(3)*1e-4)
|
||||||
>>> g.add_primitive(np.ones(3)*5e-5,np.ones(3)*5e-5,1)
|
>>> g.add_primitive(np.ones(3)*5e-5,np.ones(3)*5e-5,1)
|
||||||
cells : 64 x 64 x 64
|
cells : 64 × 64 × 64
|
||||||
size : 0.0001 x 0.0001 x 0.0001 m³
|
size : 0.0001 × 0.0001 × 0.0001 m³
|
||||||
origin: 0.0 0.0 0.0 m
|
origin: 0.0 0.0 0.0 m
|
||||||
# materials: 2
|
# materials: 2
|
||||||
|
|
||||||
|
@ -1217,8 +1267,8 @@ class Grid:
|
||||||
>>> import damask
|
>>> import damask
|
||||||
>>> g = damask.Grid(np.zeros([64]*3,int), np.ones(3)*1e-4)
|
>>> g = damask.Grid(np.zeros([64]*3,int), np.ones(3)*1e-4)
|
||||||
>>> g.add_primitive(np.ones(3,int)*32,np.zeros(3),np.inf)
|
>>> g.add_primitive(np.ones(3,int)*32,np.zeros(3),np.inf)
|
||||||
cells : 64 x 64 x 64
|
cells : 64 × 64 × 64
|
||||||
size : 0.0001 x 0.0001 x 0.0001 m³
|
size : 0.0001 × 0.0001 × 0.0001 m³
|
||||||
origin: 0.0 0.0 0.0 m
|
origin: 0.0 0.0 0.0 m
|
||||||
# materials: 2
|
# materials: 2
|
||||||
|
|
||||||
|
|
|
@ -108,7 +108,7 @@ class Orientation(Rotation,Crystal):
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
rotation : list, numpy.ndarray, Rotation, optional
|
rotation : list, numpy.ndarray, or 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.
|
Defaults to no rotation.
|
||||||
|
@ -123,7 +123,7 @@ class Orientation(Rotation,Crystal):
|
||||||
"""
|
"""
|
||||||
Return repr(self).
|
Return repr(self).
|
||||||
|
|
||||||
Give short human-readable summary.
|
Give short, human-readable summary.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
return util.srepr([Crystal.__repr__(self),
|
return util.srepr([Crystal.__repr__(self),
|
||||||
|
@ -467,24 +467,24 @@ class Orientation(Rotation,Crystal):
|
||||||
if self.family == 'cubic':
|
if self.family == 'cubic':
|
||||||
return (np.prod(np.sqrt(2)-1. >= rho_abs,axis=-1) *
|
return (np.prod(np.sqrt(2)-1. >= rho_abs,axis=-1) *
|
||||||
(1. >= np.sum(rho_abs,axis=-1))).astype(bool)
|
(1. >= np.sum(rho_abs,axis=-1))).astype(bool)
|
||||||
elif self.family == 'hexagonal':
|
if self.family == 'hexagonal':
|
||||||
return (np.prod(1. >= rho_abs,axis=-1) *
|
return (np.prod(1. >= rho_abs,axis=-1) *
|
||||||
(2. >= np.sqrt(3)*rho_abs[...,0] + rho_abs[...,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[...,1] + rho_abs[...,0]) *
|
||||||
(2. >= np.sqrt(3) + rho_abs[...,2])).astype(bool)
|
(2. >= np.sqrt(3) + rho_abs[...,2])).astype(bool)
|
||||||
elif self.family == 'tetragonal':
|
if self.family == 'tetragonal':
|
||||||
return (np.prod(1. >= rho_abs[...,:2],axis=-1) *
|
return (np.prod(1. >= rho_abs[...,:2],axis=-1) *
|
||||||
(np.sqrt(2) >= rho_abs[...,0] + rho_abs[...,1]) *
|
(np.sqrt(2) >= rho_abs[...,0] + rho_abs[...,1]) *
|
||||||
(np.sqrt(2) >= rho_abs[...,2] + 1.)).astype(bool)
|
(np.sqrt(2) >= rho_abs[...,2] + 1.)).astype(bool)
|
||||||
elif self.family == 'orthorhombic':
|
if self.family == 'orthorhombic':
|
||||||
return (np.prod(1. >= rho_abs,axis=-1)).astype(bool)
|
return (np.prod(1. >= rho_abs,axis=-1)).astype(bool)
|
||||||
elif self.family == 'monoclinic':
|
if self.family == 'monoclinic':
|
||||||
return np.logical_or( 1. >= rho_abs[...,1],
|
return np.logical_or( 1. >= rho_abs[...,1],
|
||||||
np.isnan(rho_abs[...,1]))
|
np.isnan(rho_abs[...,1]))
|
||||||
elif self.family == 'triclinic':
|
if self.family == 'triclinic':
|
||||||
return np.ones(rho_abs.shape[:-1]).astype(bool)
|
return np.ones(rho_abs.shape[:-1]).astype(bool)
|
||||||
else:
|
|
||||||
raise TypeError(f'unknown symmetry "{self.family}"')
|
raise TypeError(f'unknown symmetry "{self.family}"')
|
||||||
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
@ -510,38 +510,40 @@ class Orientation(Rotation,Crystal):
|
||||||
return ((rho[...,0] >= rho[...,1]) &
|
return ((rho[...,0] >= rho[...,1]) &
|
||||||
(rho[...,1] >= rho[...,2]) &
|
(rho[...,1] >= rho[...,2]) &
|
||||||
(rho[...,2] >= 0)).astype(bool)
|
(rho[...,2] >= 0)).astype(bool)
|
||||||
elif self.family == 'hexagonal':
|
if self.family == 'hexagonal':
|
||||||
return ((rho[...,0] >= rho[...,1]*np.sqrt(3)) &
|
return ((rho[...,0] >= rho[...,1]*np.sqrt(3)) &
|
||||||
(rho[...,1] >= 0) &
|
(rho[...,1] >= 0) &
|
||||||
(rho[...,2] >= 0)).astype(bool)
|
(rho[...,2] >= 0)).astype(bool)
|
||||||
elif self.family == 'tetragonal':
|
if self.family == 'tetragonal':
|
||||||
return ((rho[...,0] >= rho[...,1]) &
|
return ((rho[...,0] >= rho[...,1]) &
|
||||||
(rho[...,1] >= 0) &
|
(rho[...,1] >= 0) &
|
||||||
(rho[...,2] >= 0)).astype(bool)
|
(rho[...,2] >= 0)).astype(bool)
|
||||||
elif self.family == 'orthorhombic':
|
if self.family == 'orthorhombic':
|
||||||
return ((rho[...,0] >= 0) &
|
return ((rho[...,0] >= 0) &
|
||||||
(rho[...,1] >= 0) &
|
(rho[...,1] >= 0) &
|
||||||
(rho[...,2] >= 0)).astype(bool)
|
(rho[...,2] >= 0)).astype(bool)
|
||||||
elif self.family == 'monoclinic':
|
if self.family == 'monoclinic':
|
||||||
return ((rho[...,1] >= 0) &
|
return ((rho[...,1] >= 0) &
|
||||||
(rho[...,2] >= 0)).astype(bool)
|
(rho[...,2] >= 0)).astype(bool)
|
||||||
else:
|
|
||||||
return np.ones_like(rho[...,0],dtype=bool)
|
return np.ones_like(rho[...,0],dtype=bool)
|
||||||
|
|
||||||
def disorientation(self,
|
def disorientation(self,
|
||||||
other: 'Orientation',
|
other: 'Orientation',
|
||||||
return_operators: bool = False) -> object:
|
return_operators: bool = False) -> object:
|
||||||
"""
|
"""
|
||||||
Calculate disorientation between myself and given other orientation.
|
Calculate disorientation between self and given other orientation.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
other : Orientation
|
other : Orientation
|
||||||
Orientation to calculate disorientation for.
|
Orientation to calculate disorientation for.
|
||||||
Shape of other blends with shape of own rotation array.
|
Shape of other blends with shape of own rotation array.
|
||||||
For example, shapes of (2,3) for own rotations and (3,2) for other's result in (2,3,2) disorientations.
|
For example, shapes of (2,3) for own rotations
|
||||||
|
and (3,2) for other's result in (2,3,2) disorientations.
|
||||||
return_operators : bool, optional
|
return_operators : bool, optional
|
||||||
Return index pair of symmetrically equivalent orientations that result in disorientation axis falling into FZ.
|
Return index pair of symmetrically equivalent orientations
|
||||||
|
that result in disorientation axis falling into FZ.
|
||||||
Defaults to False.
|
Defaults to False.
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
|
@ -578,8 +580,8 @@ class Orientation(Rotation,Crystal):
|
||||||
>>> N = 10000
|
>>> N = 10000
|
||||||
>>> a = damask.Orientation.from_random(shape=N,family='cubic')
|
>>> a = damask.Orientation.from_random(shape=N,family='cubic')
|
||||||
>>> b = damask.Orientation.from_random(shape=N,family='cubic')
|
>>> b = damask.Orientation.from_random(shape=N,family='cubic')
|
||||||
>>> d = a.disorientation(b).as_axis_angle(degrees=True,pair=True)[1]
|
>>> n,omega = a.disorientation(b).as_axis_angle(degrees=True,pair=True)
|
||||||
>>> plt.hist(d,25)
|
>>> plt.hist(omega,25)
|
||||||
>>> plt.show()
|
>>> plt.show()
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
@ -626,6 +628,7 @@ class Orientation(Rotation,Crystal):
|
||||||
----------
|
----------
|
||||||
weights : numpy.ndarray, shape (self.shape), optional
|
weights : numpy.ndarray, shape (self.shape), optional
|
||||||
Relative weights of orientations.
|
Relative weights of orientations.
|
||||||
|
Defaults to equal weights.
|
||||||
return_cloud : bool, optional
|
return_cloud : bool, optional
|
||||||
Return the specific (symmetrically equivalent) orientations that were averaged.
|
Return the specific (symmetrically equivalent) orientations that were averaged.
|
||||||
Defaults to False.
|
Defaults to False.
|
||||||
|
@ -895,8 +898,8 @@ class Orientation(Rotation,Crystal):
|
||||||
Schmid matrix (in lab frame) of first octahedral slip system of a face-centered
|
Schmid matrix (in lab frame) of first octahedral slip system of a face-centered
|
||||||
cubic crystal in "Goss" orientation.
|
cubic crystal in "Goss" orientation.
|
||||||
|
|
||||||
>>> import damask
|
|
||||||
>>> import numpy as np
|
>>> import numpy as np
|
||||||
|
>>> import damask
|
||||||
>>> np.set_printoptions(3,suppress=True,floatmode='fixed')
|
>>> np.set_printoptions(3,suppress=True,floatmode='fixed')
|
||||||
>>> O = damask.Orientation.from_Euler_angles(phi=[0,45,0],degrees=True,lattice='cF')
|
>>> O = damask.Orientation.from_Euler_angles(phi=[0,45,0],degrees=True,lattice='cF')
|
||||||
>>> O.Schmid(N_slip=[1])
|
>>> O.Schmid(N_slip=[1])
|
||||||
|
@ -936,8 +939,9 @@ class Orientation(Rotation,Crystal):
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
-------
|
-------
|
||||||
Orientations related to self following the selected
|
rel : Orientation, shape (:,self.shape)
|
||||||
model for the orientation relationship.
|
Orientations related to self according to the selected
|
||||||
|
model for the orientation relationship.
|
||||||
|
|
||||||
Examples
|
Examples
|
||||||
--------
|
--------
|
||||||
|
|
|
@ -65,9 +65,9 @@ def _empty_like(dataset: np.ma.core.MaskedArray,
|
||||||
|
|
||||||
class Result:
|
class Result:
|
||||||
"""
|
"""
|
||||||
Add data to and export data from a DADF5 file.
|
Add data to and export data from a DADF5 (DAMASK HDF5) file.
|
||||||
|
|
||||||
A DADF5 (DAMASK HDF5) file contains DAMASK results.
|
A DADF5 file contains DAMASK results.
|
||||||
Its group/folder structure reflects the layout in material.yaml.
|
Its group/folder structure reflects the layout in material.yaml.
|
||||||
|
|
||||||
This class provides a customizable view on the DADF5 file.
|
This class provides a customizable view on the DADF5 file.
|
||||||
|
@ -93,7 +93,7 @@ class Result:
|
||||||
|
|
||||||
def __init__(self, fname: Union[str, Path]):
|
def __init__(self, fname: Union[str, Path]):
|
||||||
"""
|
"""
|
||||||
New result view bound to a HDF5 file.
|
New result view bound to a DADF5 file.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
|
@ -167,7 +167,7 @@ class Result:
|
||||||
"""
|
"""
|
||||||
Return repr(self).
|
Return repr(self).
|
||||||
|
|
||||||
Give short human-readable summary.
|
Give short, human-readable summary.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
with h5py.File(self.fname,'r') as f:
|
with h5py.File(self.fname,'r') as f:
|
||||||
|
@ -195,7 +195,7 @@ class Result:
|
||||||
homogenizations: Union[None, str, Sequence[str], bool] = None,
|
homogenizations: Union[None, str, Sequence[str], bool] = None,
|
||||||
fields: Union[None, str, Sequence[str], bool] = None) -> "Result":
|
fields: Union[None, str, Sequence[str], bool] = None) -> "Result":
|
||||||
"""
|
"""
|
||||||
Manages the visibility of the groups.
|
Manage the visibility of the groups.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
|
@ -319,15 +319,15 @@ class Result:
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
increments: (list of) int, (list of) str, or bool, optional.
|
increments: (list of) int, (list of) str, or bool, optional.
|
||||||
Number(s) of increments to select.
|
Numbers of increments to select.
|
||||||
times: (list of) float, (list of) str, or bool, optional.
|
times: (list of) float, (list of) str, or bool, optional.
|
||||||
Simulation time(s) of increments to select.
|
Simulation times of increments to select.
|
||||||
phases: (list of) str, or bool, optional.
|
phases: (list of) str, or bool, optional.
|
||||||
Name(s) of phases to select.
|
Names of phases to select.
|
||||||
homogenizations: (list of) str, or bool, optional.
|
homogenizations: (list of) str, or bool, optional.
|
||||||
Name(s) of homogenizations to select.
|
Names of homogenizations to select.
|
||||||
fields: (list of) str, or bool, optional.
|
fields: (list of) str, or bool, optional.
|
||||||
Name(s) of fields to select.
|
Names of fields to select.
|
||||||
protected: bool, optional.
|
protected: bool, optional.
|
||||||
Protection status of existing data.
|
Protection status of existing data.
|
||||||
|
|
||||||
|
@ -375,15 +375,15 @@ class Result:
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
increments: (list of) int, (list of) str, or bool, optional.
|
increments: (list of) int, (list of) str, or bool, optional.
|
||||||
Number(s) of increments to select.
|
Numbers of increments to select.
|
||||||
times: (list of) float, (list of) str, or bool, optional.
|
times: (list of) float, (list of) str, or bool, optional.
|
||||||
Simulation time(s) of increments to select.
|
Simulation times of increments to select.
|
||||||
phases: (list of) str, or bool, optional.
|
phases: (list of) str, or bool, optional.
|
||||||
Name(s) of phases to select.
|
Names of phases to select.
|
||||||
homogenizations: (list of) str, or bool, optional.
|
homogenizations: (list of) str, or bool, optional.
|
||||||
Name(s) of homogenizations to select.
|
Names of homogenizations to select.
|
||||||
fields: (list of) str, or bool, optional.
|
fields: (list of) str, or bool, optional.
|
||||||
Name(s) of fields to select.
|
Names of fields to select.
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
-------
|
-------
|
||||||
|
@ -418,15 +418,15 @@ class Result:
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
increments: (list of) int, (list of) str, or bool, optional.
|
increments: (list of) int, (list of) str, or bool, optional.
|
||||||
Number(s) of increments to select.
|
Numbers of increments to select.
|
||||||
times: (list of) float, (list of) str, or bool, optional.
|
times: (list of) float, (list of) str, or bool, optional.
|
||||||
Simulation time(s) of increments to select.
|
Simulation times of increments to select.
|
||||||
phases: (list of) str, or bool, optional.
|
phases: (list of) str, or bool, optional.
|
||||||
Name(s) of phases to select.
|
Names of phases to select.
|
||||||
homogenizations: (list of) str, or bool, optional.
|
homogenizations: (list of) str, or bool, optional.
|
||||||
Name(s) of homogenizations to select.
|
Names of homogenizations to select.
|
||||||
fields: (list of) str, or bool, optional.
|
fields: (list of) str, or bool, optional.
|
||||||
Name(s) of fields to select.
|
Names of fields to select.
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
-------
|
-------
|
||||||
|
@ -721,9 +721,11 @@ class Result:
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
P : str, optional
|
P : str, optional
|
||||||
Name of the dataset containing the first Piola-Kirchhoff stress. Defaults to 'P'.
|
Name of the dataset containing the first Piola-Kirchhoff stress.
|
||||||
|
Defaults to 'P'.
|
||||||
F : str, optional
|
F : str, optional
|
||||||
Name of the dataset containing the deformation gradient. Defaults to 'F'.
|
Name of the dataset containing the deformation gradient.
|
||||||
|
Defaults to 'F'.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
self._add_generic_pointwise(self._add_stress_Cauchy,{'P':P,'F':F})
|
self._add_generic_pointwise(self._add_stress_Cauchy,{'P':P,'F':F})
|
||||||
|
@ -1023,14 +1025,14 @@ class Result:
|
||||||
x: str,
|
x: str,
|
||||||
ord: Union[None, int, float, Literal['fro', 'nuc']] = None):
|
ord: Union[None, int, float, Literal['fro', 'nuc']] = None):
|
||||||
"""
|
"""
|
||||||
Add the norm of vector or tensor.
|
Add the norm of a vector or tensor.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
x : str
|
x : str
|
||||||
Name of vector or tensor dataset.
|
Name of vector or tensor dataset.
|
||||||
ord : {non-zero int, inf, -inf, 'fro', 'nuc'}, optional
|
ord : {non-zero int, inf, -inf, 'fro', 'nuc'}, optional
|
||||||
Order of the norm. inf means NumPy’s inf object. For details refer to numpy.linalg.norm.
|
Order of the norm. inf means NumPy's inf object. For details refer to numpy.linalg.norm.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
self._add_generic_pointwise(self._add_norm,{'x':x},{'ord':ord})
|
self._add_generic_pointwise(self._add_norm,{'x':x},{'ord':ord})
|
||||||
|
@ -1052,7 +1054,7 @@ class Result:
|
||||||
def add_stress_second_Piola_Kirchhoff(self,
|
def add_stress_second_Piola_Kirchhoff(self,
|
||||||
P: str = 'P',
|
P: str = 'P',
|
||||||
F: str = 'F'):
|
F: str = 'F'):
|
||||||
"""
|
r"""
|
||||||
Add second Piola-Kirchhoff stress calculated from first Piola-Kirchhoff stress and deformation gradient.
|
Add second Piola-Kirchhoff stress calculated from first Piola-Kirchhoff stress and deformation gradient.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
|
@ -1064,9 +1066,10 @@ class Result:
|
||||||
|
|
||||||
Notes
|
Notes
|
||||||
-----
|
-----
|
||||||
The definition of the second Piola-Kirchhoff stress (S = [F^-1 P]_sym)
|
The definition of the second Piola-Kirchhoff stress
|
||||||
|
:math:`\vb{S} = \left(\vb{F}^{-1} \vb{P}\right)_\text{sym}`
|
||||||
follows the standard definition in nonlinear continuum mechanics.
|
follows the standard definition in nonlinear continuum mechanics.
|
||||||
As such, no intermediate configuration, for instance that reached by F_p,
|
As such, no intermediate configuration, for instance that reached by :math:`\vb{F}_\text{p}`,
|
||||||
is taken into account.
|
is taken into account.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
@ -1240,10 +1243,11 @@ class Result:
|
||||||
|
|
||||||
Notes
|
Notes
|
||||||
-----
|
-----
|
||||||
The incoporation of rotational parts into the elastic and plastic
|
The presence of rotational parts in the elastic and plastic deformation gradient
|
||||||
deformation gradient requires it to use material/Lagragian strain measures
|
calls for the use of
|
||||||
(based on 'U') for plastic strains and spatial/Eulerian strain measures
|
material/Lagragian strain measures (based on 'U') for plastic strains and
|
||||||
(based on 'V') for elastic strains when calculating averages.
|
spatial/Eulerian strain measures (based on 'V') for elastic strains
|
||||||
|
when calculating averages.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
self._add_generic_pointwise(self._add_strain,{'F':F},{'t':t,'m':m})
|
self._add_generic_pointwise(self._add_strain,{'F':F},{'t':t,'m':m})
|
||||||
|
@ -1302,7 +1306,7 @@ class Result:
|
||||||
Notes
|
Notes
|
||||||
-----
|
-----
|
||||||
This function is only available for structured grids,
|
This function is only available for structured grids,
|
||||||
i.e. results from the grid solver.
|
i.e. fields resulting from the grid solver.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
self._add_generic_grid(self._add_curl,{'f':f},{'size':self.size})
|
self._add_generic_grid(self._add_curl,{'f':f},{'size':self.size})
|
||||||
|
@ -1331,7 +1335,7 @@ class Result:
|
||||||
Notes
|
Notes
|
||||||
-----
|
-----
|
||||||
This function is only available for structured grids,
|
This function is only available for structured grids,
|
||||||
i.e. results from the grid solver.
|
i.e. fields resulting from the grid solver.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
self._add_generic_grid(self._add_divergence,{'f':f},{'size':self.size})
|
self._add_generic_grid(self._add_divergence,{'f':f},{'size':self.size})
|
||||||
|
@ -1361,7 +1365,7 @@ class Result:
|
||||||
Notes
|
Notes
|
||||||
-----
|
-----
|
||||||
This function is only available for structured grids,
|
This function is only available for structured grids,
|
||||||
i.e. results from the grid solver.
|
i.e. fields resulting from the grid solver.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
self._add_generic_grid(self._add_gradient,{'f':f},{'size':self.size})
|
self._add_generic_grid(self._add_gradient,{'f':f},{'size':self.size})
|
||||||
|
@ -1379,10 +1383,10 @@ class Result:
|
||||||
----------
|
----------
|
||||||
func : function
|
func : function
|
||||||
Callback function that calculates a new dataset from one or
|
Callback function that calculates a new dataset from one or
|
||||||
more datasets per HDF5 group.
|
more datasets per DADF5 group.
|
||||||
datasets : dictionary
|
datasets : dictionary
|
||||||
Details of the datasets to be used:
|
Details of the datasets to be used:
|
||||||
{arg (name to which the data is passed in func): label (in HDF5 file)}.
|
{arg (name to which the data is passed in func): label (in DADF5 file)}.
|
||||||
args : dictionary, optional
|
args : dictionary, optional
|
||||||
Arguments parsed to func.
|
Arguments parsed to func.
|
||||||
|
|
||||||
|
@ -1462,10 +1466,10 @@ class Result:
|
||||||
----------
|
----------
|
||||||
callback : function
|
callback : function
|
||||||
Callback function that calculates a new dataset from one or
|
Callback function that calculates a new dataset from one or
|
||||||
more datasets per HDF5 group.
|
more datasets per DADF5 group.
|
||||||
datasets : dictionary
|
datasets : dictionary
|
||||||
Details of the datasets to be used:
|
Details of the datasets to be used:
|
||||||
{arg (name to which the data is passed in func): label (in HDF5 file)}.
|
{arg (name to which the data is passed in func): label (in DADF5 file)}.
|
||||||
args : dictionary, optional
|
args : dictionary, optional
|
||||||
Arguments parsed to func.
|
Arguments parsed to func.
|
||||||
|
|
||||||
|
@ -1500,7 +1504,7 @@ class Result:
|
||||||
dataset.attrs['overwritten'] = True
|
dataset.attrs['overwritten'] = True
|
||||||
else:
|
else:
|
||||||
shape = result['data'].shape
|
shape = result['data'].shape
|
||||||
if compress := (result['data'].size >= chunk_size*2):
|
if compress := result['data'].size >= chunk_size*2:
|
||||||
chunks = (chunk_size//np.prod(shape[1:]),)+shape[1:]
|
chunks = (chunk_size//np.prod(shape[1:]),)+shape[1:]
|
||||||
else:
|
else:
|
||||||
chunks = shape
|
chunks = shape
|
||||||
|
@ -1828,9 +1832,10 @@ class Result:
|
||||||
Export to VTK cell/point data.
|
Export to VTK cell/point data.
|
||||||
|
|
||||||
One VTK file per visible increment is created.
|
One VTK file per visible increment is created.
|
||||||
For point data, the VTK format is poly data (.vtp).
|
For point data, the VTK format is PolyData (.vtp).
|
||||||
For cell data, either an image (.vti) or unstructured (.vtu) dataset
|
For cell data, the file format is either ImageData (.vti)
|
||||||
is written for grid-based or mesh-based simulations, respectively.
|
or UnstructuredGrid (.vtu) for grid-based or mesh-based simulations,
|
||||||
|
respectively.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
|
@ -1961,7 +1966,7 @@ class Result:
|
||||||
for field in _match(self.visible['fields'],f_in['/'.join([inc,ty,label])].keys()):
|
for field in _match(self.visible['fields'],f_in['/'.join([inc,ty,label])].keys()):
|
||||||
p = '/'.join([inc,ty,label,field])
|
p = '/'.join([inc,ty,label,field])
|
||||||
for out in _match(output,f_in[p].keys()):
|
for out in _match(output,f_in[p].keys()):
|
||||||
f_in[p].copy(out,f_out[p])
|
f_in[p].copy(out,f_out[p])
|
||||||
|
|
||||||
|
|
||||||
def export_simulation_setup(self,
|
def export_simulation_setup(self,
|
||||||
|
|
|
@ -35,8 +35,8 @@ class Rotation:
|
||||||
Rotate vector 'a' (defined in coordinate system 'A') to
|
Rotate vector 'a' (defined in coordinate system 'A') to
|
||||||
coordinates 'b' expressed in system 'B':
|
coordinates 'b' expressed in system 'B':
|
||||||
|
|
||||||
>>> import damask
|
|
||||||
>>> import numpy as np
|
>>> import numpy as np
|
||||||
|
>>> import damask
|
||||||
>>> Q = damask.Rotation.from_random()
|
>>> Q = damask.Rotation.from_random()
|
||||||
>>> a = np.random.rand(3)
|
>>> a = np.random.rand(3)
|
||||||
>>> b = Q @ a
|
>>> b = Q @ a
|
||||||
|
@ -45,8 +45,8 @@ class Rotation:
|
||||||
|
|
||||||
Compound rotations R1 (first) and R2 (second):
|
Compound rotations R1 (first) and R2 (second):
|
||||||
|
|
||||||
>>> import damask
|
|
||||||
>>> import numpy as np
|
>>> import numpy as np
|
||||||
|
>>> import damask
|
||||||
>>> R1 = damask.Rotation.from_random()
|
>>> R1 = damask.Rotation.from_random()
|
||||||
>>> R2 = damask.Rotation.from_random()
|
>>> R2 = damask.Rotation.from_random()
|
||||||
>>> R = R2 * R1
|
>>> R = R2 * R1
|
||||||
|
@ -69,7 +69,7 @@ class Rotation:
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
rotation : list, numpy.ndarray, Rotation, optional
|
rotation : list, numpy.ndarray, or 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.
|
Defaults to no rotation.
|
||||||
|
@ -88,7 +88,7 @@ class Rotation:
|
||||||
"""
|
"""
|
||||||
Return repr(self).
|
Return repr(self).
|
||||||
|
|
||||||
Give short human-readable summary.
|
Give short, human-readable summary.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
return f'Quaternion{" " if self.quaternion.shape == (4,) else "s of shape "+str(self.quaternion.shape[:-1])+chr(10)}'\
|
return f'Quaternion{" " if self.quaternion.shape == (4,) else "s of shape "+str(self.quaternion.shape[:-1])+chr(10)}'\
|
||||||
|
|
|
@ -41,7 +41,7 @@ class Table:
|
||||||
"""
|
"""
|
||||||
Return repr(self).
|
Return repr(self).
|
||||||
|
|
||||||
Give short human-readable summary.
|
Give short, human-readable summary.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
self._relabel('shapes')
|
self._relabel('shapes')
|
||||||
|
@ -255,8 +255,8 @@ class Table:
|
||||||
"""
|
"""
|
||||||
Load from ASCII table file.
|
Load from ASCII table file.
|
||||||
|
|
||||||
Initial comments are marked by '#', the first non-comment line
|
Initial comments are marked by '#'.
|
||||||
containing the column labels.
|
The first non-comment line contains the column labels.
|
||||||
|
|
||||||
- Vector data column labels are indicated by '1_v, 2_v, ..., n_v'.
|
- Vector data column labels are indicated by '1_v, 2_v, ..., n_v'.
|
||||||
- Tensor data column labels are indicated by '3x3:1_T, 3x3:2_T, ..., 3x3:9_T'.
|
- Tensor data column labels are indicated by '3x3:1_T, 3x3:2_T, ..., 3x3:9_T'.
|
||||||
|
@ -264,7 +264,7 @@ class Table:
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
fname : file, str, or pathlib.Path
|
fname : file, str, or pathlib.Path
|
||||||
Filename or file for reading.
|
Filename or file to read.
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
-------
|
-------
|
||||||
|
@ -458,9 +458,9 @@ class Table:
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
label_old : (iterable of) str
|
label_old : (iterable of) str
|
||||||
Old column label(s).
|
Old column labels.
|
||||||
label_new : (iterable of) str
|
label_new : (iterable of) str
|
||||||
New column label(s).
|
New column labels.
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
-------
|
-------
|
||||||
|
@ -488,7 +488,7 @@ class Table:
|
||||||
label : str or list
|
label : str or list
|
||||||
Column labels for sorting.
|
Column labels for sorting.
|
||||||
ascending : bool or list, optional
|
ascending : bool or list, optional
|
||||||
Set sort order.
|
Set sort order. Defaults to True.
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
-------
|
-------
|
||||||
|
@ -574,7 +574,7 @@ class Table:
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
fname : file, str, or pathlib.Path
|
fname : file, str, or pathlib.Path
|
||||||
Filename or file for writing.
|
Filename or file to write.
|
||||||
with_labels : bool, optional
|
with_labels : bool, optional
|
||||||
Write column labels. Defaults to True.
|
Write column labels. Defaults to True.
|
||||||
|
|
||||||
|
|
|
@ -42,7 +42,7 @@ class VTK:
|
||||||
"""
|
"""
|
||||||
Return repr(self).
|
Return repr(self).
|
||||||
|
|
||||||
Give short human-readable summary.
|
Give short, human-readable summary.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
info = [self.vtk_data.__vtkname__]
|
info = [self.vtk_data.__vtkname__]
|
||||||
|
@ -163,7 +163,7 @@ class VTK:
|
||||||
cells : sequence of int, len (3)
|
cells : sequence of int, len (3)
|
||||||
Number of cells along each dimension.
|
Number of cells along each dimension.
|
||||||
size : sequence of float, len (3)
|
size : sequence of float, len (3)
|
||||||
Physical length along each dimension.
|
Edge length along each dimension.
|
||||||
origin : sequence of float, len (3), optional
|
origin : sequence of float, len (3), optional
|
||||||
Coordinates of grid origin.
|
Coordinates of grid origin.
|
||||||
|
|
||||||
|
@ -293,7 +293,7 @@ class VTK:
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
fname : str or pathlib.Path
|
fname : str or pathlib.Path
|
||||||
Filename for reading.
|
Filename to read.
|
||||||
Valid extensions are .vti, .vtu, .vtp, .vtr, and .vtk.
|
Valid extensions are .vti, .vtu, .vtp, .vtr, and .vtk.
|
||||||
dataset_type : {'ImageData', 'UnstructuredGrid', 'PolyData', 'RectilinearGrid'}, optional
|
dataset_type : {'ImageData', 'UnstructuredGrid', 'PolyData', 'RectilinearGrid'}, optional
|
||||||
Name of the vtk.vtkDataSet subclass when opening a .vtk file.
|
Name of the vtk.vtkDataSet subclass when opening a .vtk file.
|
||||||
|
@ -370,7 +370,7 @@ class VTK:
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
fname : str or pathlib.Path
|
fname : str or pathlib.Path
|
||||||
Filename for writing.
|
Filename to write.
|
||||||
parallel : bool, optional
|
parallel : bool, optional
|
||||||
Write data in parallel background process. Defaults to True.
|
Write data in parallel background process. Defaults to True.
|
||||||
compress : bool, optional
|
compress : bool, optional
|
||||||
|
@ -433,6 +433,11 @@ class VTK:
|
||||||
Data to add or replace. Each table label is individually considered.
|
Data to add or replace. Each table label is individually considered.
|
||||||
Number of rows needs to match either number of cells or number of points.
|
Number of rows needs to match either number of cells or number of points.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
updated : damask.VTK
|
||||||
|
Updated VTK-based geometry.
|
||||||
|
|
||||||
Notes
|
Notes
|
||||||
-----
|
-----
|
||||||
If the number of cells equals the number of points, the data is added to both.
|
If the number of cells equals the number of points, the data is added to both.
|
||||||
|
@ -548,7 +553,7 @@ class VTK:
|
||||||
Notes
|
Notes
|
||||||
-----
|
-----
|
||||||
The first component is shown when visualizing vector datasets
|
The first component is shown when visualizing vector datasets
|
||||||
(this includes tensor datasets because they are flattened).
|
(this includes tensor datasets as they are flattened).
|
||||||
|
|
||||||
"""
|
"""
|
||||||
# See http://compilatrix.com/article/vtk-1 for possible improvements.
|
# See http://compilatrix.com/article/vtk-1 for possible improvements.
|
||||||
|
|
|
@ -402,7 +402,7 @@ def displacement_node(size: _FloatSequence,
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
-------
|
-------
|
||||||
u_p : numpy.ndarray, shape (:,:,:,3)
|
u_n : numpy.ndarray, shape (:,:,:,3)
|
||||||
Nodal displacements.
|
Nodal displacements.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -5,7 +5,7 @@ All routines operate on numpy.ndarrays of shape (...,3,3).
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from typing import Sequence as _Sequence
|
from typing import Sequence as _Sequence#, Literal as _Literal
|
||||||
|
|
||||||
import numpy as _np
|
import numpy as _np
|
||||||
|
|
||||||
|
@ -81,7 +81,7 @@ def equivalent_strain_Mises(epsilon: _np.ndarray) -> _np.ndarray:
|
||||||
|
|
||||||
.. math::
|
.. math::
|
||||||
|
|
||||||
\epsilon_\text{vM} = \sqrt{2/3 \epsilon^\prime_{ij} \epsilon^\prime_{ij}}
|
\epsilon_\text{vM} = \sqrt{\frac{2}{3}\,\epsilon^\prime_{ij} \epsilon^\prime_{ij}}
|
||||||
|
|
||||||
where :math:`\vb*{\epsilon}^\prime` is the deviatoric part
|
where :math:`\vb*{\epsilon}^\prime` is the deviatoric part
|
||||||
of the strain tensor.
|
of the strain tensor.
|
||||||
|
@ -110,7 +110,7 @@ def equivalent_stress_Mises(sigma: _np.ndarray) -> _np.ndarray:
|
||||||
|
|
||||||
.. math::
|
.. math::
|
||||||
|
|
||||||
\sigma_\text{vM} = \sqrt{3/2 \sigma^\prime_{ij} \sigma^\prime_{ij}}
|
\sigma_\text{vM} = \sqrt{\frac{3}{2}\,\sigma^\prime_{ij} \sigma^\prime_{ij}}
|
||||||
|
|
||||||
where :math:`\vb*{\sigma}^\prime` is the deviatoric part
|
where :math:`\vb*{\sigma}^\prime` is the deviatoric part
|
||||||
of the stress tensor.
|
of the stress tensor.
|
||||||
|
@ -168,9 +168,10 @@ def rotation(T: _np.ndarray) -> _rotation.Rotation:
|
||||||
|
|
||||||
|
|
||||||
def strain(F: _np.ndarray,
|
def strain(F: _np.ndarray,
|
||||||
|
#t: _Literal['V', 'U'], should work, but rejected by SC
|
||||||
t: str,
|
t: str,
|
||||||
m: float) -> _np.ndarray:
|
m: float) -> _np.ndarray:
|
||||||
"""
|
r"""
|
||||||
Calculate strain tensor (Seth–Hill family).
|
Calculate strain tensor (Seth–Hill family).
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
|
@ -188,10 +189,19 @@ def strain(F: _np.ndarray,
|
||||||
epsilon : numpy.ndarray, shape (...,3,3)
|
epsilon : numpy.ndarray, shape (...,3,3)
|
||||||
Strain of F.
|
Strain of F.
|
||||||
|
|
||||||
|
Notes
|
||||||
|
-----
|
||||||
|
The strain is defined as:
|
||||||
|
|
||||||
|
.. math::
|
||||||
|
|
||||||
|
\vb*{\epsilon}_V^{(m)} = \frac{1}{2m} (\vb{V}^{2m} - \vb{I}) \\\\
|
||||||
|
\vb*{\epsilon}_U^{(m)} = \frac{1}{2m} (\vb{U}^{2m} - \vb{I})
|
||||||
|
|
||||||
References
|
References
|
||||||
----------
|
----------
|
||||||
https://en.wikipedia.org/wiki/Finite_strain_theory
|
| https://en.wikipedia.org/wiki/Finite_strain_theory
|
||||||
https://de.wikipedia.org/wiki/Verzerrungstensor
|
| https://de.wikipedia.org/wiki/Verzerrungstensor
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if t not in ['V', 'U']: raise ValueError('polar decomposition type not in {V, U}')
|
if t not in ['V', 'U']: raise ValueError('polar decomposition type not in {V, U}')
|
||||||
|
@ -315,8 +325,8 @@ def _polar_decomposition(T: _np.ndarray,
|
||||||
T : numpy.ndarray, shape (...,3,3)
|
T : numpy.ndarray, shape (...,3,3)
|
||||||
Tensor of which the singular values are computed.
|
Tensor of which the singular values are computed.
|
||||||
requested : sequence of {'R', 'U', 'V'}
|
requested : sequence of {'R', 'U', 'V'}
|
||||||
Requested outputs: ‘R’ for the rotation tensor,
|
Requested outputs: 'R' for the rotation tensor,
|
||||||
‘V’ for left stretch tensor, and ‘U’ for right stretch tensor.
|
'V' for left stretch tensor, and 'U' for right stretch tensor.
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
-------
|
-------
|
||||||
|
|
|
@ -21,7 +21,7 @@ def from_random(size: _FloatSequence,
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
size : sequence of float, len (3)
|
size : sequence of float, len (3)
|
||||||
Physical size of the seeding domain.
|
Edge lengths of the seeding domain.
|
||||||
N_seeds : int
|
N_seeds : int
|
||||||
Number of seeds.
|
Number of seeds.
|
||||||
cells : sequence of int, len (3), optional.
|
cells : sequence of int, len (3), optional.
|
||||||
|
@ -56,12 +56,12 @@ def from_Poisson_disc(size: _FloatSequence,
|
||||||
periodic: bool = True,
|
periodic: bool = True,
|
||||||
rng_seed: _Optional[_NumpyRngSeed] = None) -> _np.ndarray:
|
rng_seed: _Optional[_NumpyRngSeed] = None) -> _np.ndarray:
|
||||||
"""
|
"""
|
||||||
Place seeds according to a Poisson disc distribution.
|
Place seeds following a Poisson disc distribution.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
size : sequence of float, len (3)
|
size : sequence of float, len (3)
|
||||||
Physical size of the seeding domain.
|
Edge lengths of the seeding domain.
|
||||||
N_seeds : int
|
N_seeds : int
|
||||||
Number of seeds.
|
Number of seeds.
|
||||||
N_candidates : int
|
N_candidates : int
|
||||||
|
@ -70,6 +70,7 @@ def from_Poisson_disc(size: _FloatSequence,
|
||||||
Minimum acceptable distance to other seeds.
|
Minimum acceptable distance to other seeds.
|
||||||
periodic : bool, optional
|
periodic : bool, optional
|
||||||
Calculate minimum distance for periodically repeated grid.
|
Calculate minimum distance for periodically repeated grid.
|
||||||
|
Defaults to True.
|
||||||
rng_seed : {None, int, array_like[ints], SeedSequence, BitGenerator, Generator}, optional
|
rng_seed : {None, int, array_like[ints], SeedSequence, BitGenerator, Generator}, optional
|
||||||
A seed to initialize the BitGenerator. Defaults to None.
|
A seed to initialize the BitGenerator. Defaults to None.
|
||||||
If None, then fresh, unpredictable entropy will be pulled from the OS.
|
If None, then fresh, unpredictable entropy will be pulled from the OS.
|
||||||
|
@ -123,14 +124,36 @@ def from_grid(grid,
|
||||||
Consider all material IDs except those in selection. Defaults to False.
|
Consider all material IDs except those in selection. Defaults to False.
|
||||||
average : bool, optional
|
average : bool, optional
|
||||||
Seed corresponds to center of gravity of material ID cloud.
|
Seed corresponds to center of gravity of material ID cloud.
|
||||||
|
Defaults to False.
|
||||||
periodic : bool, optional
|
periodic : bool, optional
|
||||||
Center of gravity accounts for periodic boundaries.
|
Center of gravity accounts for periodic boundaries.
|
||||||
|
Defaults to True.
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
-------
|
-------
|
||||||
coords, materials : numpy.ndarray, shape (:,3); numpy.ndarray, shape (:)
|
coords, materials : numpy.ndarray, shape (:,3); numpy.ndarray, shape (:)
|
||||||
Seed coordinates in 3D space, material IDs.
|
Seed coordinates in 3D space, material IDs.
|
||||||
|
|
||||||
|
Examples
|
||||||
|
--------
|
||||||
|
Recreate seeds from Voronoi tessellation.
|
||||||
|
|
||||||
|
>>> import numpy as np
|
||||||
|
>>> import scipy.spatial
|
||||||
|
>>> import damask
|
||||||
|
>>> seeds = damask.seeds.from_random(np.ones(3),29,[128]*3)
|
||||||
|
>>> (g := damask.Grid.from_Voronoi_tessellation([128]*3,np.ones(3),seeds))
|
||||||
|
cells: 128 × 128 × 128
|
||||||
|
size: 1.0 × 1.0 × 1.0 m³
|
||||||
|
origin: 0.0 0.0 0.0 m
|
||||||
|
# materials: 29
|
||||||
|
>>> COG,matID = damask.seeds.from_grid(g,average=True)
|
||||||
|
>>> distance,ID = scipy.spatial.KDTree(COG,boxsize=g.size).query(seeds)
|
||||||
|
>>> np.max(distance) / np.linalg.norm(g.size/g.cells)
|
||||||
|
7.8057356746350415
|
||||||
|
>>> (ID == matID).all()
|
||||||
|
True
|
||||||
|
|
||||||
"""
|
"""
|
||||||
material = grid.material.reshape((-1,1),order='F')
|
material = grid.material.reshape((-1,1),order='F')
|
||||||
mask = _np.full(grid.cells.prod(),True,dtype=bool) if selection is None else \
|
mask = _np.full(grid.cells.prod(),True,dtype=bool) if selection is None else \
|
||||||
|
|
|
@ -2,6 +2,7 @@ import subprocess
|
||||||
import shlex
|
import shlex
|
||||||
import re
|
import re
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from typing import Literal
|
||||||
|
|
||||||
_marc_version = '2022.4'
|
_marc_version = '2022.4'
|
||||||
_marc_root = '/opt/msc'
|
_marc_root = '/opt/msc'
|
||||||
|
@ -54,7 +55,7 @@ class Marc:
|
||||||
|
|
||||||
def submit_job(self, model: str, job: str,
|
def submit_job(self, model: str, job: str,
|
||||||
compile: bool = False,
|
compile: bool = False,
|
||||||
optimization: str = '',
|
optimization: Literal['', 'l', 'h'] = '',
|
||||||
env = None):
|
env = None):
|
||||||
"""
|
"""
|
||||||
Assemble command line arguments and call Marc executable.
|
Assemble command line arguments and call Marc executable.
|
||||||
|
@ -68,8 +69,8 @@ class Marc:
|
||||||
compile : bool, optional
|
compile : bool, optional
|
||||||
Compile DAMASK_Marc user subroutine (and save for future use).
|
Compile DAMASK_Marc user subroutine (and save for future use).
|
||||||
Defaults to False.
|
Defaults to False.
|
||||||
optimization : str, optional
|
optimization : {'', 'l', 'h'}, optional
|
||||||
Optimization level '' (-O0), 'l' (-O1), or 'h' (-O3).
|
Optimization level '': -O0, 'l': -O1, or 'h': -O3.
|
||||||
Defaults to ''.
|
Defaults to ''.
|
||||||
env : dict, optional
|
env : dict, optional
|
||||||
Environment for execution.
|
Environment for execution.
|
||||||
|
|
|
@ -98,20 +98,17 @@ class TestGrid:
|
||||||
size=np.ones(3),
|
size=np.ones(3),
|
||||||
origin=np.ones(4))
|
origin=np.ones(4))
|
||||||
|
|
||||||
|
|
||||||
def test_invalid_materials_shape(self,default):
|
def test_invalid_materials_shape(self,default):
|
||||||
material = np.ones((3,3))
|
material = np.ones((3,3))
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
Grid(material,
|
Grid(material,
|
||||||
size=np.ones(3))
|
size=np.ones(3))
|
||||||
|
|
||||||
|
|
||||||
def test_invalid_materials_type(self,default):
|
def test_invalid_materials_type(self,default):
|
||||||
material = np.random.randint(1,300,(3,4,5))==1
|
material = np.random.randint(1,300,(3,4,5))==1
|
||||||
with pytest.raises(TypeError):
|
with pytest.raises(TypeError):
|
||||||
Grid(material)
|
Grid(material)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('directions,reflect',[
|
@pytest.mark.parametrize('directions,reflect',[
|
||||||
(['x'], False),
|
(['x'], False),
|
||||||
(['x','y','z'],True),
|
(['x','y','z'],True),
|
||||||
|
@ -126,12 +123,16 @@ class TestGrid:
|
||||||
if update: modified.save(reference)
|
if update: modified.save(reference)
|
||||||
assert Grid.load(reference) == modified
|
assert Grid.load(reference) == modified
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('directions',[(1,2,'y'),('a','b','x'),[1]])
|
@pytest.mark.parametrize('directions',[(1,2,'y'),('a','b','x'),[1]])
|
||||||
def test_mirror_invalid(self,default,directions):
|
def test_mirror_invalid(self,default,directions):
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
default.mirror(directions)
|
default.mirror(directions)
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('reflect',[True,False])
|
||||||
|
def test_mirror_order_invariant(self,default,reflect):
|
||||||
|
direction = np.array(['x','y','z'])
|
||||||
|
assert default.mirror(np.random.permutation(direction),reflect=reflect) \
|
||||||
|
== default.mirror(np.random.permutation(direction),reflect=reflect)
|
||||||
|
|
||||||
@pytest.mark.parametrize('directions',[
|
@pytest.mark.parametrize('directions',[
|
||||||
['x'],
|
['x'],
|
||||||
|
@ -147,22 +148,30 @@ class TestGrid:
|
||||||
if update: modified.save(reference)
|
if update: modified.save(reference)
|
||||||
assert Grid.load(reference) == modified
|
assert Grid.load(reference) == modified
|
||||||
|
|
||||||
|
def test_flip_order_invariant(self,default):
|
||||||
|
direction = np.array(['x','y','z'])
|
||||||
|
assert default.flip(np.random.permutation(direction)) \
|
||||||
|
== default.flip(np.random.permutation(direction))
|
||||||
|
|
||||||
def test_flip_invariant(self,default):
|
def test_flip_mirrored_invariant(self,default):
|
||||||
assert default == default.flip([])
|
direction = np.random.permutation(['x','y','z'])
|
||||||
|
assert default.mirror(direction,True) == default.mirror(direction,True).flip(direction)
|
||||||
|
|
||||||
|
def test_flip_equal_halfspin(self,default):
|
||||||
|
direction = ['x','y','z']
|
||||||
|
i = np.random.choice(3)
|
||||||
|
assert default.rotate(Rotation.from_axis_angle(np.hstack((np.identity(3)[i],180)),degrees=True)) \
|
||||||
|
== default.flip(direction[:i]+direction[i+1:])
|
||||||
|
|
||||||
@pytest.mark.parametrize('direction',[['x'],['x','y']])
|
@pytest.mark.parametrize('direction',[['x'],['x','y']])
|
||||||
def test_flip_double(self,default,direction):
|
def test_flip_double(self,default,direction):
|
||||||
assert default == default.flip(direction).flip(direction)
|
assert default == default.flip(direction).flip(direction)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('directions',[(1,2,'y'),('a','b','x'),[1]])
|
@pytest.mark.parametrize('directions',[(1,2,'y'),('a','b','x'),[1]])
|
||||||
def test_flip_invalid(self,default,directions):
|
def test_flip_invalid(self,default,directions):
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
default.flip(directions)
|
default.flip(directions)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('distance',[1.,np.sqrt(3)])
|
@pytest.mark.parametrize('distance',[1.,np.sqrt(3)])
|
||||||
@pytest.mark.parametrize('selection',[None,1,[1],[1,2,3]])
|
@pytest.mark.parametrize('selection',[None,1,[1],[1,2,3]])
|
||||||
@pytest.mark.parametrize('periodic',[True,False])
|
@pytest.mark.parametrize('periodic',[True,False])
|
||||||
|
@ -184,7 +193,6 @@ class TestGrid:
|
||||||
assert random.clean(selection=None,invert_selection=True,rng_seed=0) == random.clean(rng_seed=0) and \
|
assert random.clean(selection=None,invert_selection=True,rng_seed=0) == random.clean(rng_seed=0) and \
|
||||||
random.clean(selection=None,invert_selection=False,rng_seed=0) == random.clean(rng_seed=0)
|
random.clean(selection=None,invert_selection=False,rng_seed=0) == random.clean(rng_seed=0)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('cells',[
|
@pytest.mark.parametrize('cells',[
|
||||||
(10,11,10),
|
(10,11,10),
|
||||||
[10,13,10],
|
[10,13,10],
|
||||||
|
@ -201,7 +209,6 @@ class TestGrid:
|
||||||
if update: modified.save(reference)
|
if update: modified.save(reference)
|
||||||
assert Grid.load(reference) == modified
|
assert Grid.load(reference) == modified
|
||||||
|
|
||||||
|
|
||||||
def test_renumber(self,default):
|
def test_renumber(self,default):
|
||||||
material = default.material.copy()
|
material = default.material.copy()
|
||||||
for m in np.unique(material):
|
for m in np.unique(material):
|
||||||
|
@ -213,7 +220,6 @@ class TestGrid:
|
||||||
assert not default == modified
|
assert not default == modified
|
||||||
assert default == modified.renumber()
|
assert default == modified.renumber()
|
||||||
|
|
||||||
|
|
||||||
def test_assemble(self):
|
def test_assemble(self):
|
||||||
cells = np.random.randint(8,16,3)
|
cells = np.random.randint(8,16,3)
|
||||||
N = cells.prod()
|
N = cells.prod()
|
||||||
|
@ -221,7 +227,6 @@ class TestGrid:
|
||||||
idx = np.random.randint(0,N,N).reshape(cells)
|
idx = np.random.randint(0,N,N).reshape(cells)
|
||||||
assert (idx == g.assemble(idx).material).all
|
assert (idx == g.assemble(idx).material).all
|
||||||
|
|
||||||
|
|
||||||
def test_substitute(self,default):
|
def test_substitute(self,default):
|
||||||
offset = np.random.randint(1,500)
|
offset = np.random.randint(1,500)
|
||||||
modified = Grid(default.material + offset,
|
modified = Grid(default.material + offset,
|
||||||
|
@ -257,7 +262,6 @@ class TestGrid:
|
||||||
modified.rotate(Rotation.from_axis_angle(axis_angle,degrees=True))
|
modified.rotate(Rotation.from_axis_angle(axis_angle,degrees=True))
|
||||||
assert default == modified
|
assert default == modified
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('Eulers',[[32.0,68.0,21.0],
|
@pytest.mark.parametrize('Eulers',[[32.0,68.0,21.0],
|
||||||
[0.0,32.0,240.0]])
|
[0.0,32.0,240.0]])
|
||||||
def test_rotate(self,default,update,ref_path,Eulers):
|
def test_rotate(self,default,update,ref_path,Eulers):
|
||||||
|
@ -267,7 +271,6 @@ class TestGrid:
|
||||||
if update: modified.save(reference)
|
if update: modified.save(reference)
|
||||||
assert Grid.load(reference) == modified
|
assert Grid.load(reference) == modified
|
||||||
|
|
||||||
|
|
||||||
def test_canvas_extend(self,default):
|
def test_canvas_extend(self,default):
|
||||||
cells = default.cells
|
cells = default.cells
|
||||||
cells_add = np.random.randint(0,30,(3))
|
cells_add = np.random.randint(0,30,(3))
|
||||||
|
@ -364,14 +367,12 @@ class TestGrid:
|
||||||
assert random.vicinity_offset(selection=None,invert_selection=False) == random.vicinity_offset() and \
|
assert random.vicinity_offset(selection=None,invert_selection=False) == random.vicinity_offset() and \
|
||||||
random.vicinity_offset(selection=None,invert_selection=True ) == random.vicinity_offset()
|
random.vicinity_offset(selection=None,invert_selection=True ) == random.vicinity_offset()
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('periodic',[True,False])
|
@pytest.mark.parametrize('periodic',[True,False])
|
||||||
def test_vicinity_offset_invariant(self,default,periodic):
|
def test_vicinity_offset_invariant(self,default,periodic):
|
||||||
offset = default.vicinity_offset(selection=[default.material.max()+1,
|
offset = default.vicinity_offset(selection=[default.material.max()+1,
|
||||||
default.material.min()-1])
|
default.material.min()-1])
|
||||||
assert np.all(offset.material==default.material)
|
assert np.all(offset.material==default.material)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('periodic',[True,False])
|
@pytest.mark.parametrize('periodic',[True,False])
|
||||||
def test_tessellation_approaches(self,periodic):
|
def test_tessellation_approaches(self,periodic):
|
||||||
cells = np.random.randint(10,20,3)
|
cells = np.random.randint(10,20,3)
|
||||||
|
@ -382,7 +383,6 @@ class TestGrid:
|
||||||
Laguerre = Grid.from_Laguerre_tessellation(cells,size,seeds,np.ones(N_seeds),np.arange(N_seeds)+5,periodic)
|
Laguerre = Grid.from_Laguerre_tessellation(cells,size,seeds,np.ones(N_seeds),np.arange(N_seeds)+5,periodic)
|
||||||
assert Laguerre == Voronoi
|
assert Laguerre == Voronoi
|
||||||
|
|
||||||
|
|
||||||
def test_Laguerre_weights(self):
|
def test_Laguerre_weights(self):
|
||||||
cells = np.random.randint(10,20,3)
|
cells = np.random.randint(10,20,3)
|
||||||
size = np.random.random(3) + 1.0
|
size = np.random.random(3) + 1.0
|
||||||
|
@ -394,7 +394,6 @@ class TestGrid:
|
||||||
Laguerre = Grid.from_Laguerre_tessellation(cells,size,seeds,weights,periodic=np.random.random()>0.5)
|
Laguerre = Grid.from_Laguerre_tessellation(cells,size,seeds,weights,periodic=np.random.random()>0.5)
|
||||||
assert np.all(Laguerre.material == ms)
|
assert np.all(Laguerre.material == ms)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('approach',['Laguerre','Voronoi'])
|
@pytest.mark.parametrize('approach',['Laguerre','Voronoi'])
|
||||||
def test_tessellate_bicrystal(self,approach):
|
def test_tessellate_bicrystal(self,approach):
|
||||||
cells = np.random.randint(5,10,3)*2
|
cells = np.random.randint(5,10,3)*2
|
||||||
|
@ -408,7 +407,6 @@ class TestGrid:
|
||||||
grid = Grid.from_Voronoi_tessellation(cells,size,seeds, periodic=np.random.random()>0.5)
|
grid = Grid.from_Voronoi_tessellation(cells,size,seeds, periodic=np.random.random()>0.5)
|
||||||
assert np.all(grid.material == material)
|
assert np.all(grid.material == material)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('surface',['Schwarz P',
|
@pytest.mark.parametrize('surface',['Schwarz P',
|
||||||
'Double Primitive',
|
'Double Primitive',
|
||||||
'Schwarz D',
|
'Schwarz D',
|
||||||
|
@ -450,7 +448,6 @@ class TestGrid:
|
||||||
grid = Grid.from_minimal_surface(cells,np.ones(3),surface,threshold)
|
grid = Grid.from_minimal_surface(cells,np.ones(3),surface,threshold)
|
||||||
assert np.isclose(np.count_nonzero(grid.material==1)/np.prod(grid.cells),.5,rtol=1e-3)
|
assert np.isclose(np.count_nonzero(grid.material==1)/np.prod(grid.cells),.5,rtol=1e-3)
|
||||||
|
|
||||||
|
|
||||||
def test_from_table(self):
|
def test_from_table(self):
|
||||||
cells = np.random.randint(60,100,3)
|
cells = np.random.randint(60,100,3)
|
||||||
size = np.ones(3)+np.random.rand(3)
|
size = np.ones(3)+np.random.rand(3)
|
||||||
|
@ -462,7 +459,6 @@ class TestGrid:
|
||||||
g = Grid.from_table(t,'coords',['indicator','z'])
|
g = Grid.from_table(t,'coords',['indicator','z'])
|
||||||
assert g.N_materials == g.cells[0]*2 and (g.material[:,:,-1]-g.material[:,:,0] == cells[0]).all()
|
assert g.N_materials == g.cells[0]*2 and (g.material[:,:,-1]-g.material[:,:,0] == cells[0]).all()
|
||||||
|
|
||||||
|
|
||||||
def test_from_table_recover(self,tmp_path):
|
def test_from_table_recover(self,tmp_path):
|
||||||
cells = np.random.randint(60,100,3)
|
cells = np.random.randint(60,100,3)
|
||||||
size = np.ones(3)+np.random.rand(3)
|
size = np.ones(3)+np.random.rand(3)
|
||||||
|
@ -472,7 +468,6 @@ class TestGrid:
|
||||||
t = Table({'c':3,'m':1},np.column_stack((coords.reshape(-1,3,order='F'),grid.material.flatten(order='F'))))
|
t = Table({'c':3,'m':1},np.column_stack((coords.reshape(-1,3,order='F'),grid.material.flatten(order='F'))))
|
||||||
assert grid.sort().renumber() == Grid.from_table(t,'c',['m'])
|
assert grid.sort().renumber() == Grid.from_table(t,'c',['m'])
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('periodic',[True,False])
|
@pytest.mark.parametrize('periodic',[True,False])
|
||||||
@pytest.mark.parametrize('direction',['x','y','z',['x','y'],'zy','xz',['x','y','z']])
|
@pytest.mark.parametrize('direction',['x','y','z',['x','y'],'zy','xz',['x','y','z']])
|
||||||
@pytest.mark.xfail(int(vtk.vtkVersion.GetVTKVersion().split('.')[0])<8, reason='missing METADATA')
|
@pytest.mark.xfail(int(vtk.vtkVersion.GetVTKVersion().split('.')[0])<8, reason='missing METADATA')
|
||||||
|
@ -497,7 +492,6 @@ class TestGrid:
|
||||||
np.allclose(grain.size,point.size) and \
|
np.allclose(grain.size,point.size) and \
|
||||||
(grain.sort().material == point.material+1).all()
|
(grain.sort().material == point.material+1).all()
|
||||||
|
|
||||||
|
|
||||||
def test_load_DREAM3D_reference(self,ref_path,update):
|
def test_load_DREAM3D_reference(self,ref_path,update):
|
||||||
current = Grid.load_DREAM3D(ref_path/'measured.dream3d')
|
current = Grid.load_DREAM3D(ref_path/'measured.dream3d')
|
||||||
reference = Grid.load(ref_path/'measured.vti')
|
reference = Grid.load(ref_path/'measured.vti')
|
||||||
|
|
Loading…
Reference in New Issue