diff --git a/PRIVATE b/PRIVATE index e2301f7d1..281e7eb84 160000 --- a/PRIVATE +++ b/PRIVATE @@ -1 +1 @@ -Subproject commit e2301f7d12ff0ae12218d9b58e33a814eb5431c9 +Subproject commit 281e7eb84f76a2974a50eb54faf35ea25ec89b20 diff --git a/VERSION b/VERSION index b85a6ab34..3f1edac2f 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -v3.0.0-alpha-633-g086b215d9 +v3.0.0-alpha-726-g1f59f6301 diff --git a/cmake/Compiler-Intel.cmake b/cmake/Compiler-Intel.cmake index 6d96ff42d..719ed885b 100644 --- a/cmake/Compiler-Intel.cmake +++ b/cmake/Compiler-Intel.cmake @@ -98,11 +98,12 @@ set (DEBUG_FLAGS "${DEBUG_FLAGS} -ftrapuv") set (DEBUG_FLAGS "${DEBUG_FLAGS} -fpe-all=0") # ... capture all floating-point exceptions, sets -ftz automatically -set (DEBUG_FLAGS "${DEBUG_FLAGS} -warn") +# disable due to compiler bug https://community.intel.com/t5/Intel-Fortran-Compiler/false-positive-stand-f18-and-IEEE-SELECTED-REAL-KIND/m-p/1227336 +#set (DEBUG_FLAGS "${DEBUG_FLAGS} -warn") # enables warnings ... -set (DEBUG_FLAGS "${DEBUG_FLAGS} errors") +#set (DEBUG_FLAGS "${DEBUG_FLAGS} errors") # ... warnings are changed to errors -set (DEBUG_FLAGS "${DEBUG_FLAGS},stderrors") +#set (DEBUG_FLAGS "${DEBUG_FLAGS},stderrors") # ... warnings about Fortran standard violations are changed to errors set (DEBUG_FLAGS "${DEBUG_FLAGS} -debug-parameters all") diff --git a/examples/SpectralMethod/Polycrystal/material.yaml b/examples/SpectralMethod/Polycrystal/material.yaml index 04775be4c..9bfc97ca3 100644 --- a/examples/SpectralMethod/Polycrystal/material.yaml +++ b/examples/SpectralMethod/Polycrystal/material.yaml @@ -108,19 +108,19 @@ material: phase: Aluminum: - elasticity: {C_11: 106.75e9, C_12: 60.41e9, C_44: 28.34e9, type: hooke} - generic: - output: [F, P, F_e, F_p, L_p, O] lattice: fcc - plasticity: - N_sl: [12] - a_sl: 2.25 - atol_xi: 1.0 - dot_gamma_0_sl: 0.001 - h_0_sl_sl: 75e6 - h_sl_sl: [1, 1, 1.4, 1.4, 1.4, 1.4] - n_sl: 20 - output: [xi_sl] - type: phenopowerlaw - xi_0_sl: [31e6] - xi_inf_sl: [63e6] + mech: + output: [F, P, F_e, F_p, L_p, O] + elasticity: {C_11: 106.75e9, C_12: 60.41e9, C_44: 28.34e9, type: hooke} + plasticity: + N_sl: [12] + a_sl: 2.25 + atol_xi: 1.0 + dot_gamma_0_sl: 0.001 + h_0_sl_sl: 75e6 + h_sl_sl: [1, 1, 1.4, 1.4, 1.4, 1.4] + n_sl: 20 + output: [xi_sl] + type: phenopowerlaw + xi_0_sl: [31e6] + xi_inf_sl: [63e6] diff --git a/python/damask/__init__.py b/python/damask/__init__.py index 600f64138..9d0350337 100644 --- a/python/damask/__init__.py +++ b/python/damask/__init__.py @@ -15,12 +15,12 @@ from . import seeds # noqa from . import mechanics # noqa from . import solver # noqa from . import grid_filters # noqa -from ._lattice import Symmetry, Lattice# noqa -from ._table import Table # noqa +from . import lattice # noqa from ._rotation import Rotation # noqa +from ._orientation import Orientation # noqa +from ._table import Table # noqa from ._vtk import VTK # noqa from ._colormap import Colormap # noqa -from ._orientation import Orientation # noqa from ._config import Config # noqa from ._configmaterial import ConfigMaterial # noqa from ._geom import Geom # noqa diff --git a/python/damask/_asciitable.py b/python/damask/_asciitable.py index 9d762369a..de7596aea 100644 --- a/python/damask/_asciitable.py +++ b/python/damask/_asciitable.py @@ -385,38 +385,3 @@ class ASCIItable(): self.data = np.loadtxt(self.__IO__['in'],usecols=use,ndmin=2) return labels_missing - -# ------------------------------------------------------------------ - def data_write(self): - """Write current data array and report alive output back.""" - if len(self.data) == 0: return True - - if isinstance(self.data[0],list): - return self.output_write(['\t'.join(map(self._quote,items)) for items in self.data]) - else: - return self.output_write( '\t'.join(map(self._quote,self.data))) - -# ------------------------------------------------------------------ - def data_writeArray(self): - """Write whole numpy array data.""" - for row in self.data: - try: - output = list(map(repr,row)) - except Exception: - output = [repr(row)] - - try: - self.__IO__['out'].write('\t'.join(output) + '\n') - except Exception: - pass - -# ------------------------------------------------------------------ - def data_append(self, - what): - if isinstance(what, str): - self.data += [what] - else: - try: - for item in what: self.data_append(item) - except TypeError: - self.data += [str(what)] diff --git a/python/damask/_configmaterial.py b/python/damask/_configmaterial.py index ed45f2662..4f3eba816 100644 --- a/python/damask/_configmaterial.py +++ b/python/damask/_configmaterial.py @@ -3,8 +3,8 @@ import copy import numpy as np from . import Config -from . import Lattice from . import Rotation +from . import Orientation class ConfigMaterial(Config): """Material configuration.""" @@ -24,6 +24,20 @@ class ConfigMaterial(Config): super().save(fname,**kwargs) + @classmethod + def load(cls,fname='material.yaml'): + """ + Load from yaml file. + + Parameters + ---------- + fname : file, str, or pathlib.Path, optional + Filename or file for writing. Defaults to 'material.yaml'. + + """ + return super(ConfigMaterial,cls).load(fname) + + @staticmethod def from_table(table,constituents={},**kwargs): """ @@ -138,7 +152,7 @@ class ConfigMaterial(Config): for k,v in self['phase'].items(): if 'lattice' in v: try: - Lattice(v['lattice']) + Orientation(lattice=v['lattice']) except KeyError: s = v['lattice'] print(f"Invalid lattice: '{s}' in phase '{k}'") diff --git a/python/damask/_geom.py b/python/damask/_geom.py index d3b375bf6..3d73861ad 100644 --- a/python/damask/_geom.py +++ b/python/damask/_geom.py @@ -20,7 +20,7 @@ class Geom: 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 ---------- @@ -34,28 +34,10 @@ class Geom: Comment lines. """ - 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) - - 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)] + self.material = material + self.size = size + self.origin = origin + self.comments = comments def __repr__(self): @@ -113,13 +95,68 @@ class Geom: 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 def grid(self): + """Grid dimension of geometry.""" return np.asarray(self.material.shape) @property def N_materials(self): + """Number of (unique) material indices within geometry.""" return np.unique(self.material).size @@ -132,7 +169,7 @@ class Geom: ---------- fname : str or or pathlib.Path 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') @@ -153,7 +190,7 @@ class Geom: Parameters ---------- - fname : str or file handle + fname : str, pathlib.Path, or file handle Geometry file to read. """ @@ -221,26 +258,26 @@ class Geom: fname : str Filename of the DREAM.3D file base_group : str - Name of the group (folder) below 'DataContainers'. For example - 'SyntheticVolumeDataContainer'. + Name of the group (folder) below 'DataContainers', + for example 'SyntheticVolumeDataContainer'. point_data : str, optional - Name of the group (folder) containing the point wise material data, - for example 'CellData'. Defaults to None, in which case points consecutively numbered. + Name of the group (folder) containing the pointwise material data, + for example 'CellData'. Defaults to None, in which case points are consecutively numbered. material : str, optional - Name of the dataset containing the material ID. Defaults to - 'FeatureIds'. + Name of the dataset containing the material ID. + Defaults to 'FeatureIds'. """ root_dir ='DataContainers' f = h5py.File(fname, 'r') 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')][()] + size = f[path.join(g,'SPACING')][()] * grid 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 \ - np.reshape(f[path.join(group_pointwise,material)],grid.prod()) + ma = np.arange(grid.prod(),dtype=int) \ + 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')) @@ -248,18 +285,18 @@ class Geom: @staticmethod def from_table(table,coordinates,labels): """ - Load an ASCII table. + Derive geometry from an ASCII table. Parameters ---------- table : damask.Table Table that contains material information. 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). labels : str or list of str 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)) @@ -293,8 +330,8 @@ class Geom: weights : numpy.ndarray of shape (seeds.shape[0]) 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 ID of the seeds. Defaults to None, in which case materials are - consecutively numbered. + Material ID of the seeds. + Defaults to None, in which case materials are consecutively numbered. periodic : Boolean, optional Perform a periodic tessellation. Defaults to True. @@ -342,8 +379,8 @@ class Geom: seeds : numpy.ndarray of shape (:,3) 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 ID of the seeds. Defaults to None, in which case materials are - consecutively numbered. + Material ID of the seeds. + Defaults to None, in which case materials are consecutively numbered. periodic : Boolean, optional Perform a periodic tessellation. Defaults to True. @@ -438,19 +475,19 @@ class Geom: 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, 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 - 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 - 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], @@ -465,7 +502,7 @@ class Geom: def save(self,fname,compress=True): """ - Store as vtk rectilinear grid. + Store as VTK rectilinear grid. Parameters ---------- @@ -521,20 +558,20 @@ class Geom: Parameters ---------- - dimension : int or float numpy.ndarray of shape(3) + dimension : int or float numpy.ndarray of shape (3) Dimension (diameter/side length) of the primitive. If given as integers, grid point locations (cell centers) are addressed. If given as floats, coordinates are addressed. - center : int or float numpy.ndarray of shape(3) + center : int or float numpy.ndarray of shape (3) Center of the primitive. If given as integers, grid point - locations (cell centers) are addressed. - If given as floats, coordinates are addressed. - exponent : numpy.ndarray of shape(3) or float + coordinates (cell centers) are addressed. + If given as floats, coordinates in space are addressed. + exponent : numpy.ndarray of shape (3) or float Exponents for the three axes. 0 gives octahedron (ǀxǀ^(2^0) + ǀyǀ^(2^0) + ǀzǀ^(2^0) < 1) 1 gives sphere (ǀxǀ^(2^1) + ǀyǀ^(2^1) + ǀzǀ^(2^1) < 1) 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 Rotation of primitive. Defaults to no rotation. inverse : Boolean, optional @@ -544,25 +581,27 @@ class Geom: Repeat primitive over boundaries. Defaults to True. """ - # normalized 'radius' and center - r = np.array(dimension)/self.grid/2.0 if np.array(dimension).dtype in np.sctypes['int'] else \ - np.array(dimension)/self.size/2.0 - c = (np.array(center) + .5)/self.grid if np.array(center).dtype in np.sctypes['int'] else \ - (np.array(center) - self.origin)/self.size + # radius and center + r = np.array(dimension)/2.0*self.size/self.grid if np.array(dimension).dtype in np.sctypes['int'] else \ + np.array(dimension)/2.0 + c = (np.array(center) + .5)*self.size/self.grid if np.array(center).dtype in np.sctypes['int'] else \ + (np.array(center) - self.origin) - coords = grid_filters.cell_coord0(self.grid,np.ones(3)) \ - - ((np.ones(3)-(1./self.grid if np.array(center).dtype in np.sctypes['int'] else 0))*0.5 if periodic else c) # periodic center is always at CoG + coords = grid_filters.cell_coord0(self.grid,self.size, + -(0.5*(self.size + (self.size/self.grid + if np.array(center).dtype in np.sctypes['int'] else + 0)) if periodic else c)) coords_rot = R.broadcast_to(tuple(self.grid))@coords with np.errstate(all='ignore'): mask = np.sum(np.power(coords_rot/r,2.0**np.array(exponent)),axis=-1) > 1.0 if periodic: # translate back to center - mask = np.roll(mask,((c-np.ones(3)*.5)*self.grid).astype(int),(0,1,2)) + mask = np.roll(mask,((c/self.size-0.5)*self.grid).round().astype(int),(0,1,2)) - fill_ = np.full_like(self.material,np.nanmax(self.material)+1 if fill is None else fill) - - return Geom(material = np.where(np.logical_not(mask) if inverse else mask, self.material,fill_), + return Geom(material = np.where(np.logical_not(mask) if inverse else mask, + self.material, + np.nanmax(self.material)+1 if fill is None else fill), size = self.size, origin = self.origin, comments = self.comments+[util.execution_stamp('Geom','add_primitive')], @@ -689,7 +728,7 @@ class Geom: 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) return Geom(material = renumbered.reshape(self.grid), @@ -785,7 +824,7 @@ class Geom: """ def mp(entry,mapper): return mapper[entry] if entry in mapper else entry - + mp = np.vectorize(mp) mapper = dict(zip(from_material,to_material)) @@ -796,6 +835,20 @@ class Geom: ) + def sort(self): + """Sort material indices such that min(material) is located at (0,0,0).""" + a = self.material.flatten(order='F') + from_ma = pd.unique(a) + sort_idx = np.argsort(from_ma) + ma = np.unique(a)[sort_idx][np.searchsorted(from_ma,a,sorter = sort_idx)] + + return Geom(material = ma.reshape(self.grid,order='F'), + size = self.size, + origin = self.origin, + comments = self.comments+[util.execution_stamp('Geom','sort')], + ) + + def vicinity_offset(self,vicinity=1,offset=None,trigger=[],periodic=True): """ Offset material index of points in the vicinity of xxx. @@ -811,7 +864,7 @@ class Geom: Defaults to 1. offset : int, optional Offset (positive or negative) to tag material indices, - defaults to material.max() + 1. + defaults to material.max()+1. trigger : list of ints, optional List of material indices that trigger a change. Defaults to [], meaning that any different neighbor triggers a change. @@ -822,15 +875,11 @@ class Geom: def tainted_neighborhood(stencil,trigger): me = stencil[stencil.shape[0]//2] - if len(trigger) == 0: - return np.any(stencil != me) - if me in trigger: - trigger = set(trigger) - trigger.remove(me) - trigger = list(trigger) - return np.any(np.in1d(stencil,np.array(trigger))) + return np.any(stencil != me + if len(trigger) == 0 else + np.in1d(stencil,np.array(list(set(trigger) - {me})))) - offset_ = np.nanmax(self.material) if offset is None else offset + offset_ = np.nanmax(self.material)+1 if offset is None else offset mask = ndimage.filters.generic_filter(self.material, tainted_neighborhood, size=1+2*vicinity, diff --git a/python/damask/_lattice.py b/python/damask/_lattice.py deleted file mode 100644 index 143fa50f1..000000000 --- a/python/damask/_lattice.py +++ /dev/null @@ -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 diff --git a/python/damask/_orientation.py b/python/damask/_orientation.py index 0bb0e1bc8..e0a00e0a0 100644 --- a/python/damask/_orientation.py +++ b/python/damask/_orientation.py @@ -1,202 +1,1234 @@ import numpy as np -from . import Lattice from . import Rotation +from . import util +from . import mechanics -class Orientation: # ToDo: make subclass of lattice and Rotation? +__parameter_doc__ = \ + """lattice : str + Either a crystal family out of [triclinic, monoclinic, orthorhombic, tetragonal, hexagonal, cubic] + or a Bravais lattice out of [aP, mP, mS, oP, oS, oI, oF, tP, tI, hP, cP, cI, cF]. + When specifying a Bravais lattice, additional lattice parameters might be required: + a : float, optional + Length of lattice parameter "a". + b : float, optional + Length of lattice parameter "b". + c : float, optional + Length of lattice parameter "c". + alpha : float, optional + Angle between b and c lattice basis. + beta : float, optional + Angle between c and a lattice basis. + gamma : float, optional + Angle between a and b lattice basis. + degrees : bool, optional + Angles are given in degrees. Defaults to False. + + """ + + +def extend_docstring(): + """Decorator: Append Orientation parameter documentation to function's docstring.""" + def _decorator(func): + func.__doc__ += __parameter_doc__ + return func + return _decorator + + +def extended_docstring(f): + """Decorator: Combine Orientation parameter documentation with another function's docstring.""" + def _decorator(func): + func.__doc__ = f.__doc__ + __parameter_doc__ + return func + return _decorator + + +class Orientation(Rotation): """ - Crystallographic orientation. + Representation of crystallographic orientation as combination of rotation and either crystal family or Bravais lattice. - A crystallographic orientation contains a rotation and a lattice. + The crystal family is one of Orientation.crystal_families: + + - triclinic + - monoclinic + - orthorhombic + - tetragonal + - hexagonal + - cubic + + and enables symmetry-related operations such as + "equivalent", "reduced", "disorientation", "IPF_color", or "to_SST". + + The Bravais lattice is one of Orientation.lattice_symmetries: + + - aP : triclinic primitive + - mP : monoclinic primitive + - mS : ... base-centered + - oP : orthorhombic primitive + - oS : ... base-centered + - oI : ... body-centered + - oF : ... face-centered + - tP : tetragonal primitive + - tI : ... body-centered + - hP : hexagonal primitive + - cP : cubic primitive + - cI : ... body-centered + - cF : ... face-centered + + and inherits the corresponding crystal family. + Specifying a Bravais lattice, compared to just the crystal family, + extends the functionality of Orientation objects to include operations such as + "Schmid", "related", or "to_pole" that require a lattice type and its parameters. + + Examples + -------- + An array of 3 x 5 random orientations reduced to the fundamental zone of tetragonal symmetry: + >>> damask.Orientation.from_random(shape=(3,5),lattice='tetragonal').reduced + + Disorientation between two specific orientations of hexagonal symmetry: + >>> a = damask.Orientation.from_Eulers(phi=[123,32,21],degrees=True,lattice='hexagonal') + >>> b = damask.Orientation.from_Eulers(phi=[104,11,87],degrees=True,lattice='hexagonal') + >>> a.disorientation(b) + + Inverse pole figure color of the e_3 direction for a crystal in "Cube" orientation with cubic symmetry: + >>> o = damask.Orientation(lattice='cubic') + >>> o.IPF_color(o.to_SST(np.array([0,0,1]))) + + Schmid matrix (in lab frame) of slip systems of a face-centered cubic crystal in "Goss" orientation: + >>> damask.Orientation.from_Eulers(phi=[0,45,0],degrees=True,lattice='cF').Schmid('slip') """ - __slots__ = ['rotation','lattice'] + crystal_families = ['triclinic', + 'monoclinic', + 'orthorhombic', + 'tetragonal', + 'hexagonal', + 'cubic'] - def __repr__(self): - """Report lattice type and orientation.""" - return self.lattice.__repr__()+'\n'+self.rotation.__repr__() + lattice_symmetries = { + 'aP': 'triclinic', - def __init__(self, rotation, lattice): + 'mP': 'monoclinic', + 'mS': 'monoclinic', + + 'oP': 'orthorhombic', + 'oS': 'orthorhombic', + 'oI': 'orthorhombic', + 'oF': 'orthorhombic', + + 'tP': 'tetragonal', + 'tI': 'tetragonal', + + 'hP': 'hexagonal', + + 'cP': 'cubic', + 'cI': 'cubic', + 'cF': 'cubic', + } + + + @extend_docstring() + def __init__(self, + rotation = None, + lattice = None, + a = None,b = None,c = None, + alpha = None,beta = None,gamma = None, + degrees = False, + **kwargs): """ - New orientation from rotation and lattice. + Initialize orientation object. Parameters ---------- - rotation : Rotation - Rotation specifying the lattice orientation. - lattice : Lattice - Lattice type of the crystal. + rotation : list, numpy.ndarray, Rotation, optional + Unit quaternion in positive real hemisphere. + Use .from_quaternion to perform a sanity check. + Defaults to no rotation. """ - if isinstance(lattice, Lattice): + from damask.lattice import kinematics + + Rotation.__init__(self) if rotation is None else Rotation.__init__(self,rotation=rotation) + + if ( lattice is not None + and lattice not in self.lattice_symmetries + and lattice not in self.crystal_families): + raise KeyError(f'Lattice "{lattice}" is unknown') + + self.family = None + self.lattice = None + self.a = None + self.b = None + self.c = None + self.alpha = None + self.beta = None + self.gamma = None + self.kinematics = None + + if lattice in self.lattice_symmetries: + self.family = self.lattice_symmetries[lattice] self.lattice = lattice - else: - self.lattice = Lattice(lattice) # assume string + self.a = 1 if a is None else a + self.b = b + self.c = c + self.alpha = (np.radians(alpha) if degrees else alpha) if alpha is not None else None + self.beta = (np.radians(beta) if degrees else beta) if beta is not None else None + self.gamma = (np.radians(gamma) if degrees else gamma) if gamma is not None else None - if isinstance(rotation, Rotation): - self.rotation = rotation - else: - self.rotation = Rotation.from_quaternion(rotation) # assume quaternion + self.a = float(self.a) if self.a is not None else \ + (self.b / self.ratio['b'] if self.b is not None and self.ratio['b'] is not None else + self.c / self.ratio['c'] if self.c is not None and self.ratio['c'] is not None else None) + self.b = float(self.b) if self.b is not None else \ + (self.a * self.ratio['b'] if self.a is not None and self.ratio['b'] is not None else + self.c / self.ratio['c'] * self.ratio['b'] + if self.c is not None and self.ratio['b'] is not None and self.ratio['c'] is not None else None) + self.c = float(self.c) if self.c is not None else \ + (self.a * self.ratio['c'] if self.a is not None and self.ratio['c'] is not None else + self.b / self.ratio['b'] * self.ratio['c'] + if self.c is not None and self.ratio['b'] is not None and self.ratio['c'] is not None else None) + self.alpha = self.alpha if self.alpha is not None else self.immutable['alpha'] if 'alpha' in self.immutable else None + self.beta = self.beta if self.beta is not None else self.immutable['beta'] if 'beta' in self.immutable else None + self.gamma = self.gamma if self.gamma is not None else self.immutable['gamma'] if 'gamma' in self.immutable else None - def __getitem__(self,item): - """Iterate over leading/leftmost dimension of Orientation array.""" - return self.__class__(self.rotation[item],self.lattice) + if \ + (self.a is None) \ + or (self.b is None or ('b' in self.immutable and self.b != self.immutable['b'] * self.a)) \ + or (self.c is None or ('c' in self.immutable and self.c != self.immutable['c'] * self.b)) \ + or (self.alpha is None or ('alpha' in self.immutable and self.alpha != self.immutable['alpha'])) \ + or (self.beta is None or ( 'beta' in self.immutable and self.beta != self.immutable['beta'])) \ + or (self.gamma is None or ('gamma' in self.immutable and self.gamma != self.immutable['gamma'])): + raise ValueError (f'Incompatible parameters {self.parameters} for crystal family {self.family}') + + if np.any(np.array([self.alpha,self.beta,self.gamma]) <= 0): + raise ValueError ('Lattice angles must be positive') + if np.any([np.roll([self.alpha,self.beta,self.gamma],r)[0] + > np.sum(np.roll([self.alpha,self.beta,self.gamma],r)[1:]) for r in range(3)]): + raise ValueError ('Each lattice angle must be less than sum of others') + + if self.lattice in kinematics: + master = kinematics[self.lattice] + self.kinematics = {} + for m in master: + self.kinematics[m] = {'direction':master[m][:,0:3],'plane':master[m][:,3:6]} \ + if master[m].shape[-1] == 6 else \ + {'direction':self.Bravais_to_Miller(uvtw=master[m][:,0:4]), + 'plane': self.Bravais_to_Miller(hkil=master[m][:,4:8])} + elif lattice in self.crystal_families: + self.family = lattice - # ToDo: Discuss vectorization/calling signature - def disorientation(self, - other, - SST = True, - symmetries = False): + def __repr__(self): + """Represent.""" + return '\n'.join(([] if self.lattice is None else [f'Bravais lattice {self.lattice}']) + + ([] if self.family is None else [f'Crystal family {self.family}']) + + [super().__repr__()]) + + + def __copy__(self,**kwargs): + """Copy.""" + return self.__class__(rotation=kwargs['rotation'] if 'rotation' in kwargs else self.quaternion, + lattice =kwargs['lattice'] if 'lattice' in kwargs else self.lattice + if self.lattice is not None else self.family, + a =kwargs['a'] if 'a' in kwargs else self.a, + b =kwargs['b'] if 'b' in kwargs else self.b, + c =kwargs['c'] if 'c' in kwargs else self.c, + alpha =kwargs['alpha'] if 'alpha' in kwargs else self.alpha, + beta =kwargs['beta'] if 'beta' in kwargs else self.beta, + gamma =kwargs['gamma'] if 'gamma' in kwargs else self.gamma, + degrees =kwargs['degrees'] if 'degrees' in kwargs else None, + ) + + copy = __copy__ + + + def __eq__(self,other): """ - Disorientation between myself and given other orientation. + Equal to other. - Rotation axis falls into SST if SST == True. - - Currently requires same symmetry for both orientations. - Look into A. Heinz and P. Neumann 1991 for cases with differing sym. + Parameters + ---------- + other : Orientation + Orientation to check for equality. """ - if self.lattice.symmetry != other.lattice.symmetry: - raise NotImplementedError('disorientation between different symmetry classes not supported yet.') + return super().__eq__(other) \ + and self.family == other.family \ + and self.lattice == other.lattice \ + and self.parameters == other.parameters - mySymEqs = self.equivalent if SST else self.equivalent[0] #ToDo: This is just me! # take all or only first sym operation - otherSymEqs = other.equivalent - for i,sA in enumerate(mySymEqs): - aInv = sA.rotation.inversed() - for j,sB in enumerate(otherSymEqs): - b = sB.rotation - r = b*aInv - for k in range(2): - r.inverse() - breaker = self.lattice.in_FZ(r.as_Rodrigues(vector=True)) \ - and (not SST or other.lattice.in_disorientation_SST(r.as_Rodrigues(vector=True))) - if breaker: break - if breaker: break - if breaker: break + def __matmul__(self,other): + """ + Rotation of vector, second or fourth order tensor, or rotation object. + + Parameters + ---------- + other : numpy.ndarray, Rotation, or Orientation + Vector, second or fourth order tensor, or rotation object that is rotated. + + Returns + ------- + other_rot : numpy.ndarray or Rotation + Rotated vector, second or fourth order tensor, or rotation object. + + """ + return self.copy(rotation=Rotation.__matmul__(self,Rotation(other.quaternion))) \ + if isinstance(other,self.__class__) else \ + Rotation.__matmul__(self,other) + + + @classmethod + @extended_docstring(Rotation.from_random) + def from_random(cls,**kwargs): + return cls(rotation=Rotation.from_random(**kwargs),**kwargs) + + + @classmethod + @extended_docstring(Rotation.from_quaternion) + def from_quaternion(cls,**kwargs): + return cls(rotation=Rotation.from_quaternion(**kwargs),**kwargs) + + + @classmethod + @extended_docstring(Rotation.from_Eulers) + def from_Eulers(cls,**kwargs): + return cls(rotation=Rotation.from_Eulers(**kwargs),**kwargs) + + + @classmethod + @extended_docstring(Rotation.from_axis_angle) + def from_axis_angle(cls,**kwargs): + return cls(rotation=Rotation.from_axis_angle(**kwargs),**kwargs) + + + @classmethod + @extended_docstring(Rotation.from_basis) + def from_basis(cls,**kwargs): + return cls(rotation=Rotation.from_basis(**kwargs),**kwargs) + + + @classmethod + @extended_docstring(Rotation.from_matrix) + def from_matrix(cls,**kwargs): + return cls(rotation=Rotation.from_matrix(**kwargs),**kwargs) + + + @classmethod + @extended_docstring(Rotation.from_Rodrigues) + def from_Rodrigues(cls,**kwargs): + return cls(rotation=Rotation.from_Rodrigues(**kwargs),**kwargs) + + + @classmethod + @extended_docstring(Rotation.from_homochoric) + def from_homochoric(cls,**kwargs): + return cls(rotation=Rotation.from_homochoric(**kwargs),**kwargs) + + + @classmethod + @extended_docstring(Rotation.from_cubochoric) + def from_cubochoric(cls,**kwargs): + return cls(rotation=Rotation.from_cubochoric(**kwargs),**kwargs) + + + @classmethod + @extended_docstring(Rotation.from_spherical_component) + def from_spherical_component(cls,**kwargs): + return cls(rotation=Rotation.from_spherical_component(**kwargs),**kwargs) + + + @classmethod + @extended_docstring(Rotation.from_fiber_component) + def from_fiber_component(cls,**kwargs): + return cls(rotation=Rotation.from_fiber_component(**kwargs),**kwargs) + + + @classmethod + @extend_docstring() + def from_directions(cls,uvw,hkl,**kwargs): + """ + Initialize orientation object from two crystallographic directions. + + Parameters + ---------- + uvw : list, numpy.ndarray of shape (...,3) + lattice direction aligned with lab frame x-direction. + hkl : list, numpy.ndarray of shape (...,3) + lattice plane normal aligned with lab frame z-direction. + + """ + o = cls(**kwargs) + x = o.to_frame(uvw=uvw) + z = o.to_frame(hkl=hkl) + om = np.stack([x,np.cross(z,x),z],axis=-2) + return o.copy(rotation=Rotation.from_matrix(mechanics.transpose(om/np.linalg.norm(om,axis=-1,keepdims=True)))) - return (Orientation(r,self.lattice), i,j, k == 1) if symmetries else r # disorientation ... - # ... own sym, other sym, - # self-->other: True, self<--other: False @property - def in_FZ(self): - """Check if orientations fall into Fundamental Zone.""" - return self.lattice.in_FZ(self.rotation.as_Rodrigues(vector=True)) + def symmetry_operations(self): + """Symmetry operations as Rotations.""" + if self.family == '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.family == '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.family == '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.family == '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 ], + ] + elif self.family == 'monoclinic': + sym_quats = [ + [ 1.0,0.0,0.0,0.0 ], + [ 0.0,0.0,1.0,0.0 ], + ] + elif self.family == 'triclinic': + sym_quats = [ + [ 1.0,0.0,0.0,0.0 ], + ] + else: + raise KeyError(f'Crystal family "{self.family}" is unknown') + + return Rotation.from_quaternion(sym_quats,accept_homomorph=True) @property def equivalent(self): """ - Orientations which are symmetrically equivalent. + Orientations that are symmetrically equivalent. - One dimension (length according to number of symmetrically equivalent orientations) + One dimension (length corresponds to number of symmetrically equivalent orientations) is added to the left of the Rotation array. """ - o = self.lattice.symmetry.symmetry_operations - o = o.reshape(o.shape[:1]+(1,)*len(self.rotation.shape)+(4,)) - o = Rotation(np.broadcast_to(o,o.shape[:1]+self.rotation.quaternion.shape)) + if self.family is None: + raise ValueError('Missing crystal symmetry') - s = np.broadcast_to(self.rotation.quaternion,o.shape[:1]+self.rotation.quaternion.shape) + o = self.symmetry_operations.broadcast_to(self.symmetry_operations.shape+self.shape,mode='right') + return self.copy(rotation=o@Rotation(self.quaternion).broadcast_to(o.shape,mode='left')) - return self.__class__(o@Rotation(s),self.lattice) + + @property + def reduced(self): + """Select symmetrically equivalent orientation that falls into fundamental zone according to symmetry.""" + if self.family is None: + raise ValueError('Missing crystal symmetry') + + eq = self.equivalent + ok = eq.in_FZ + ok &= np.cumsum(ok,axis=0) == 1 + loc = np.where(ok) + sort = 0 if len(loc) == 1 else np.lexsort(loc[:0:-1]) + return eq[ok][sort].reshape(self.shape) + + + @property + def in_FZ(self): + """ + Check whether orientation falls into fundamental zone of own symmetry. + + Returns + ------- + in : numpy.ndarray of quaternion.shape + Boolean array indicating whether Rodrigues-Frank vector falls into fundamental zone. + + Notes + ----- + Fundamental zones in Rodrigues space are point-symmetric around origin. + + References + ---------- + A. Heinz and P. Neumann, Acta Crystallographica Section A 47:780-789, 1991 + https://doi.org/10.1107/S0108767391006864 + + """ + if self.family is None: + raise ValueError('Missing crystal symmetry') + + rho_abs = np.abs(self.as_Rodrigues(vector=True)) + + with np.errstate(invalid='ignore'): + # using '*'/prod for 'and' + if self.family == 'cubic': + return (np.prod(np.sqrt(2)-1. >= rho_abs,axis=-1) * + (1. >= np.sum(rho_abs,axis=-1))).astype(np.bool) + elif self.family == 'hexagonal': + return (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])).astype(np.bool) + elif self.family == 'tetragonal': + return (np.prod(1. >= rho_abs[...,:2],axis=-1) * + (np.sqrt(2) >= rho_abs[...,0] + rho_abs[...,1]) * + (np.sqrt(2) >= rho_abs[...,2] + 1.)).astype(np.bool) + elif self.family == 'orthorhombic': + return (np.prod(1. >= rho_abs,axis=-1)).astype(np.bool) + elif self.family == 'monoclinic': + return (1. >= rho_abs[...,1]).astype(np.bool) + else: + return np.all(np.isfinite(rho_abs),axis=-1) + + + @property + def in_disorientation_FZ(self): + """ + Check whether orientation falls into fundamental zone of disorientations. + + Returns + ------- + in : numpy.ndarray of quaternion.shape + Boolean array indicating whether Rodrigues-Frank vector falls into disorientation FZ. + + References + ---------- + A. Heinz and P. Neumann, Acta Crystallographica Section A 47:780-789, 1991 + https://doi.org/10.1107/S0108767391006864 + + """ + if self.family is None: + raise ValueError('Missing crystal symmetry') + + rho = self.as_Rodrigues(vector=True) + + with np.errstate(invalid='ignore'): + if self.family == 'cubic': + return ((rho[...,0] >= rho[...,1]) & + (rho[...,1] >= rho[...,2]) & + (rho[...,2] >= 0)).astype(np.bool) + elif self.family == 'hexagonal': + return ((rho[...,0] >= rho[...,1]*np.sqrt(3)) & + (rho[...,1] >= 0) & + (rho[...,2] >= 0)).astype(np.bool) + elif self.family == 'tetragonal': + return ((rho[...,0] >= rho[...,1]) & + (rho[...,1] >= 0) & + (rho[...,2] >= 0)).astype(np.bool) + elif self.family == 'orthorhombic': + return ((rho[...,0] >= 0) & + (rho[...,1] >= 0) & + (rho[...,2] >= 0)).astype(np.bool) + elif self.family == 'monoclinic': + return ((rho[...,1] >= 0) & + (rho[...,2] >= 0)).astype(np.bool) + else: + return np.ones_like(rho[...,0],dtype=bool) + + + def relation_operations(self,model,return_lattice=False): + """ + Crystallographic orientation relationships for phase transformations. + + Parameters + ---------- + model : str + Name of orientation relationship. + return_lattice : bool, optional + Return the target lattice in addition. + + Returns + ------- + operations : Rotations + Rotations characterizing the orientation relationship. + + 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 + + """ + from damask.lattice import relations + + if model not in relations: + raise KeyError(f'Orientation relationship "{model}" is unknown') + r = relations[model] + + if self.lattice not in r: + raise KeyError(f'Relationship "{model}" not supported for lattice "{self.lattice}"') + + sl = self.lattice + ol = (set(r)-{sl}).pop() + m = r[sl] + o = r[ol] + + p_,_p = np.zeros(m.shape[:-1]+(3,)),np.zeros(o.shape[:-1]+(3,)) + p_[...,0,:] = m[...,0,:] if m.shape[-1] == 3 else self.Bravais_to_Miller(uvtw=m[...,0,0:4]) + p_[...,1,:] = m[...,1,:] if m.shape[-1] == 3 else self.Bravais_to_Miller(hkil=m[...,1,0:4]) + _p[...,0,:] = o[...,0,:] if o.shape[-1] == 3 else self.Bravais_to_Miller(uvtw=o[...,0,0:4]) + _p[...,1,:] = o[...,1,:] if o.shape[-1] == 3 else self.Bravais_to_Miller(hkil=o[...,1,0:4]) + + return (Rotation.from_parallel(p_,_p),ol) \ + if return_lattice else \ + Rotation.from_parallel(p_,_p) def related(self,model): """ - Orientations related by the given orientation relationship. + Orientations derived from the given relationship. One dimension (length according to number of related orientations) is added to the left of the Rotation array. """ - o = Rotation.from_matrix(self.lattice.relation_operations(model)['rotations']).as_quaternion() - o = o.reshape(o.shape[:1]+(1,)*len(self.rotation.shape)+(4,)) - o = Rotation(np.broadcast_to(o,o.shape[:1]+self.rotation.quaternion.shape)) - - s = np.broadcast_to(self.rotation.quaternion,o.shape[:1]+self.rotation.quaternion.shape) - - return self.__class__(o@Rotation(s),self.lattice.relation_operations(model)['lattice']) + o,lattice = self.relation_operations(model,return_lattice=True) + target = Orientation(lattice=lattice) + o = o.broadcast_to(o.shape+self.shape,mode='right') + return self.copy(rotation=o@Rotation(self.quaternion).broadcast_to(o.shape,mode='left'), + lattice=lattice, + b = self.b if target.ratio['b'] is None else self.a*target.ratio['b'], + c = self.c if target.ratio['c'] is None else self.a*target.ratio['c'], + alpha = None if 'alpha' in target.immutable else self.alpha, + beta = None if 'beta' in target.immutable else self.beta, + gamma = None if 'gamma' in target.immutable else self.gamma, + ) @property - def reduced(self): - """Transform orientation to fall into fundamental zone according to symmetry.""" - eq = self.equivalent - in_FZ = eq.in_FZ - - # remove duplicates (occur for highly symmetric orientations) - found = np.zeros_like(in_FZ[0],dtype=bool) - q = self.rotation.quaternion[0] - for s in range(in_FZ.shape[0]): - #something fishy... why does q needs to be initialized? - q = np.where(np.expand_dims(np.logical_and(in_FZ[s],~found),-1),eq.rotation.quaternion[s],q) - found = np.logical_or(in_FZ[s],found) - - return self.__class__(q,self.lattice) + def parameters(self): + """Return lattice parameters a, b, c, alpha, beta, gamma.""" + return (self.a,self.b,self.c,self.alpha,self.beta,self.gamma) - def inverse_pole(self,axis,proper=False,SST=True): - """Axis rotated according to orientation (using crystal symmetry to ensure location falls into SST).""" - if SST: - eq = self.equivalent - pole = eq.rotation @ np.broadcast_to(axis/np.linalg.norm(axis),eq.rotation.shape+(3,)) - in_SST = self.lattice.in_SST(pole,proper=proper) - - # remove duplicates (occur for highly symmetric orientations) - found = np.zeros_like(in_SST[0],dtype=bool) - p = pole[0] - for s in range(in_SST.shape[0]): - p = np.where(np.expand_dims(np.logical_and(in_SST[s],~found),-1),pole[s],p) - found = np.logical_or(in_SST[s],found) - - return p + @property + def immutable(self): + """Return immutable parameters of own lattice.""" + if self.family == 'triclinic': + return {} + if self.family == 'monoclinic': + return { + 'alpha': np.pi/2., + 'gamma': np.pi/2., + } + if self.family == 'orthorhombic': + return { + 'alpha': np.pi/2., + 'beta': np.pi/2., + 'gamma': np.pi/2., + } + if self.family == 'tetragonal': + return { + 'b': 1.0, + 'alpha': np.pi/2., + 'beta': np.pi/2., + 'gamma': np.pi/2., + } + if self.family == 'hexagonal': + return { + 'b': 1.0, + 'alpha': np.pi/2., + 'beta': np.pi/2., + 'gamma': 2.*np.pi/3., + } + if self.family == 'cubic': + return { + 'b': 1.0, + 'c': 1.0, + 'alpha': np.pi/2., + 'beta': np.pi/2., + 'gamma': np.pi/2., + } else: - return self.rotation @ np.broadcast_to(axis/np.linalg.norm(axis),self.rotation.shape+(3,)) + raise KeyError(f'Crystal family "{self.family}" is unknown') + @property + def ratio(self): + """Return axes ratios of own lattice.""" + _ratio = { 'hexagonal': {'c': np.sqrt(8./3.)}} + + return dict(b = self.immutable['b'] + if 'b' in self.immutable else + _ratio[self.family]['b'] if self.family in _ratio and 'b' in _ratio[self.family] else None, + c = self.immutable['c'] + if 'c' in self.immutable else + _ratio[self.family]['c'] if self.family in _ratio and 'c' in _ratio[self.family] else None, + ) + + + @property + def basis_real(self): + """ + Calculate orthogonal real space crystal basis. + + References + ---------- + C.T. Young and J.L. Lytton, J. Appl. Phys. 43:1408–1417, 1972 + "Computer Generation and Identification of Kikuchi Projections" + https://doi.org/10.1063/1.1661333 + + """ + if None in self.parameters: + raise KeyError('Missing crystal lattice parameters') + return np.array([ + [1,0,0], + [np.cos(self.gamma),np.sin(self.gamma),0], + [np.cos(self.beta), + (np.cos(self.alpha)-np.cos(self.beta)*np.cos(self.gamma)) /np.sin(self.gamma), + np.sqrt(1 - np.cos(self.alpha)**2 - np.cos(self.beta)**2 - np.cos(self.gamma)**2 + + 2 * np.cos(self.alpha) * np.cos(self.beta) * np.cos(self.gamma))/np.sin(self.gamma)], + ],dtype=float).T \ + * np.array([self.a,self.b,self.c]) + + + @property + def basis_reciprocal(self): + """Calculate reciprocal (dual) crystal basis.""" + return np.linalg.inv(self.basis_real.T) + + + def in_SST(self,vector,proper=False): + """ + Check whether given crystal frame vector falls into standard stereographic triangle of own symmetry. + + Parameters + ---------- + vector : numpy.ndarray of shape (...,3) + Vector to check. + proper : bool, optional + Consider only vectors with z >= 0, hence combine two neighboring SSTs. + Defaults to False. + + Returns + ------- + in : numpy.ndarray of shape (...) + Boolean array indicating whether vector falls into SST. + + References + ---------- + Bases are computed from + + >>> basis = { + ... 'cubic' : np.linalg.inv(np.array([[0.,0.,1.], # direction of red + ... [1.,0.,1.]/np.sqrt(2.), # green + ... [1.,1.,1.]/np.sqrt(3.)]).T), # blue + ... 'hexagonal' : np.linalg.inv(np.array([[0.,0.,1.], # direction of red + ... [1.,0.,0.], # green + ... [np.sqrt(3.),1.,0.]/np.sqrt(4.)]).T), # blue + ... 'tetragonal' : np.linalg.inv(np.array([[0.,0.,1.], # direction of red + ... [1.,0.,0.], # green + ... [1.,1.,0.]/np.sqrt(2.)]).T), # blue + ... 'orthorhombic': np.linalg.inv(np.array([[0.,0.,1.], # direction of red + ... [1.,0.,0.], # green + ... [0.,1.,0.]]).T), # blue + ... } + + """ + if not isinstance(vector,np.ndarray) or vector.shape[-1] != 3: + raise ValueError('Input is not a field of three-dimensional vectors.') + + if self.family == '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.family == '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.family == '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.family == '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 + return np.ones_like(vector[...,0],bool) + + if proper: + components_proper = np.around(np.einsum('...ji,...i', + np.broadcast_to(basis['proper'], vector.shape+(3,)), + vector), 12) + components_improper = np.around(np.einsum('...ji,...i', + np.broadcast_to(basis['improper'], vector.shape+(3,)), + vector), 12) + return np.all(components_proper >= 0.0,axis=-1) \ + | np.all(components_improper >= 0.0,axis=-1) + else: + components = np.around(np.einsum('...ji,...i', + np.broadcast_to(basis['improper'], vector.shape+(3,)), + np.block([vector[...,:2],np.abs(vector[...,2:3])])), 12) + + return np.all(components >= 0.0,axis=-1) + + + def IPF_color(self,vector,proper=False): + """ + Map vector to RGB color within standard stereographic triangle of own symmetry. + + Parameters + ---------- + vector : numpy.ndarray of shape (...,3) + Vector to colorize. + proper : bool, optional + Consider only vectors with z >= 0, hence combine two neighboring SSTs (with mirrored colors). + Defaults to False. + + Returns + ------- + rgb : numpy.ndarray of shape (...,3) + RGB array of IPF colors. + + References + ---------- + Bases are computed from + + >>> basis = { + ... 'cubic' : np.linalg.inv(np.array([[0.,0.,1.], # direction of red + ... [1.,0.,1.]/np.sqrt(2.), # green + ... [1.,1.,1.]/np.sqrt(3.)]).T), # blue + ... 'hexagonal' : np.linalg.inv(np.array([[0.,0.,1.], # direction of red + ... [1.,0.,0.], # green + ... [np.sqrt(3.),1.,0.]/np.sqrt(4.)]).T), # blue + ... 'tetragonal' : np.linalg.inv(np.array([[0.,0.,1.], # direction of red + ... [1.,0.,0.], # green + ... [1.,1.,0.]/np.sqrt(2.)]).T), # blue + ... 'orthorhombic': np.linalg.inv(np.array([[0.,0.,1.], # direction of red + ... [1.,0.,0.], # green + ... [0.,1.,0.]]).T), # blue + ... } + + """ + if vector.shape[-1] != 3: + raise ValueError('Input is not a field of three-dimensional vectors.') + + if self.family == '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.family == '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.family == '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.family == '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 + return np.zeros_like(vector) + + if proper: + components_proper = np.around(np.einsum('...ji,...i', + np.broadcast_to(basis['proper'], vector.shape+(3,)), + vector), 12) + components_improper = np.around(np.einsum('...ji,...i', + np.broadcast_to(basis['improper'], vector.shape+(3,)), + vector), 12) + in_SST = np.all(components_proper >= 0.0,axis=-1) \ + | np.all(components_improper >= 0.0,axis=-1) + components = np.where((in_SST & np.all(components_proper >= 0.0,axis=-1))[...,np.newaxis], + components_proper,components_improper) + else: + components = np.around(np.einsum('...ji,...i', + np.broadcast_to(basis['improper'], vector.shape+(3,)), + np.block([vector[...,:2],np.abs(vector[...,2:3])])), 12) + + in_SST = np.all(components >= 0.0,axis=-1) + + with np.errstate(invalid='ignore',divide='ignore'): + rgb = (components/np.linalg.norm(components,axis=-1,keepdims=True))**0.5 # smoothen color ramps + rgb = np.clip(rgb,0.,1.) # clip intensity + rgb /= np.max(rgb,axis=-1,keepdims=True) # normalize to (HS)V = 1 + rgb[np.broadcast_to(~in_SST[...,np.newaxis],rgb.shape)] = 0.0 + return rgb + + + def disorientation(self,other,return_operators=False): + """ + Calculate disorientation between myself and given other orientation. + + Parameters + ---------- + other : Orientation + Orientation to calculate disorientation for. + 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. + return_operators : bool, optional + Return index pair of symmetrically equivalent orientations that result in disorientation axis falling into FZ. + Defaults to False. + + Returns + ------- + disorientation : Orientation + Disorientation between self and other. + operators : numpy.ndarray int of shape (...,2), conditional + Index of symmetrically equivalent orientation that rotated vector to the SST. + + Notes + ----- + Currently requires same crystal family for both orientations. + For extension to cases with differing symmetry see A. Heinz and P. Neumann 1991 and 10.1107/S0021889808016373. + + """ + if self.family is None or other.family is None: + raise ValueError('Missing crystal symmetry') + if self.family != other.family: + raise NotImplementedError('Disorientation between different crystal families not supported yet.') + + blend = util.shapeblender(self.shape,other.shape) + s = self.equivalent + o = other.equivalent + + s_ = s.reshape((s.shape[0],1)+ self.shape).broadcast_to((s.shape[0],o.shape[0])+blend,mode='right') + o_ = o.reshape((1,o.shape[0])+other.shape).broadcast_to((s.shape[0],o.shape[0])+blend,mode='right') + r_ = s_.misorientation(o_) + _r = ~r_ + + forward = r_.in_FZ & r_.in_disorientation_FZ + reverse = _r.in_FZ & _r.in_disorientation_FZ + ok = forward | reverse + ok &= (np.cumsum(ok.reshape((-1,)+ok.shape[2:]),axis=0) == 1).reshape(ok.shape) + r = np.where(np.any(forward[...,np.newaxis],axis=(0,1),keepdims=True), + r_.quaternion, + _r.quaternion) + loc = np.where(ok) + sort = 0 if len(loc) == 2 else np.lexsort(loc[:1:-1]) + quat = r[ok][sort].reshape(blend+(4,)) + + return ( + (self.copy(rotation=quat), + (np.vstack(loc[:2]).T)[sort].reshape(blend+(2,))) + if return_operators else + self.copy(rotation=quat) + ) + + + def average(self,weights=None,return_cloud=False): + """ + Return orientation average over last dimension. + + Parameters + ---------- + weights : numpy.ndarray, optional + Relative weights of orientations. + return_cloud : bool, optional + Return the set of symmetrically equivalent orientations that was used in averaging. + Defaults to False. + + Returns + ------- + average : Orientation + Weighted average of original Orientation field. + cloud : Orientations, conditional + Set of symmetrically equivalent orientations that were used in averaging. + + References + ---------- + J.C. Glez and J. Driver, J. Appl. Cryst. 34:280-288, 2001 + "Orientation distribution analysis in deformed grains" + https://doi.org/10.1107/S0021889801003077 + + """ + if self.family is None: + raise ValueError('Missing crystal symmetry') - def IPF_color(self,axis): #ToDo axis or direction? - """TSL color of inverse pole figure for given axis.""" eq = self.equivalent - pole = eq.rotation @ np.broadcast_to(axis/np.linalg.norm(axis),eq.rotation.shape+(3,)) - in_SST, color = self.lattice.in_SST(pole,color=True) - - # remove duplicates (occur for highly symmetric orientations) - found = np.zeros_like(in_SST[0],dtype=bool) - c = color[0] - for s in range(in_SST.shape[0]): - c = np.where(np.expand_dims(np.logical_and(in_SST[s],~found),-1),color[s],c) - found = np.logical_or(in_SST[s],found) - - return c + m = eq.misorientation(self[...,0].reshape((1,)+self.shape[:-1]+(1,)) + .broadcast_to(eq.shape))\ + .as_axis_angle()[...,3] + r = Rotation(np.squeeze(np.take_along_axis(eq.quaternion, + np.argmin(m,axis=0)[np.newaxis,...,np.newaxis], + axis=0), + axis=0)) + return ( + (self.copy(rotation=Rotation(r).average(weights)), + self.copy(rotation=Rotation(r))) + if return_cloud else + self.copy(rotation=Rotation(r).average(weights)) + ) - # ToDo: Discuss vectorization/calling signature - @staticmethod - def from_average(orientations, - weights = []): - """Create orientation from average of list of orientations.""" - # further read: Orientation distribution analysis in deformed grains - # https://doi.org/10.1107/S0021889801003077 - if not all(isinstance(item, Orientation) for item in orientations): - raise TypeError("Only instances of Orientation can be averaged.") + def to_SST(self,vector,proper=False,return_operators=False): + """ + Rotate vector to ensure it falls into (improper or proper) standard stereographic triangle of crystal symmetry. - closest = [] - ref = orientations[0] - for o in orientations: - closest.append(o.equivalent[ - ref.disorientation(o, - SST = False, # select (o[ther]'s) sym orientation - symmetries = True)[2]].rotation) # with lowest misorientation + Parameters + ---------- + vector : numpy.ndarray of shape (...,3) + Lab frame vector to align with crystal frame direction. + Shape of other blends with shape of own rotation array. + For example, a rotation array of shape (3,2) and a (2,4) vector array result in (3,2,4) outputs. + proper : bool, optional + Consider only vectors with z >= 0, hence combine two neighboring SSTs. + Defaults to False. + return_operators : bool, optional + Return the symmetrically equivalent orientation that rotated vector to SST. + Defaults to False. - return Orientation(Rotation.from_average(closest,weights),ref.lattice) + Returns + ------- + vector_SST : numpy.ndarray of shape (...,3) + Rotated vector falling into SST. + operators : numpy.ndarray int of shape (...), conditional + Index of symmetrically equivalent orientation that rotated vector to SST. + + """ + if self.family is None: + raise ValueError('Missing crystal symmetry') + + eq = self.equivalent + blend = util.shapeblender(eq.shape,vector.shape[:-1]) + poles = eq.broadcast_to(blend,mode='right') @ np.broadcast_to(vector,blend+(3,)) + ok = self.in_SST(poles,proper=proper) + ok &= np.cumsum(ok,axis=0) == 1 + loc = np.where(ok) + sort = 0 if len(loc) == 1 else np.lexsort(loc[:0:-1]) + return ( + (poles[ok][sort].reshape(blend[1:]+(3,)), (np.vstack(loc[:1]).T)[sort].reshape(blend[1:])) + if return_operators else + poles[ok][sort].reshape(blend[1:]+(3,)) + ) - # ToDo: Discuss vectorization/calling signature - def average(self,other): - """Calculate the average rotation.""" - return Orientation.from_average([self,other]) + @classmethod + def Bravais_to_Miller(cls,uvtw=None,hkil=None): + """ + Transform 4 Miller–Bravais indices to 3 Miller indices of crystal direction [uvw] or plane normal (hkl). + + Parameters + ---------- + uvtw | hkil : numpy.ndarray of shape (...,4) + Miller–Bravais indices of crystallographic direction [uvtw] or plane normal (hkil). + + Returns + ------- + uvw | hkl : numpy.ndarray of shape (...,3) + Miller indices of [uvw] direction or (hkl) plane normal. + + """ + if (uvtw is not None) ^ (hkil is None): + raise KeyError('Specify either "uvtw" or "hkil"') + axis,basis = (np.array(uvtw),np.array([[1,0,-1,0], + [0,1,-1,0], + [0,0, 0,1]])) \ + if hkil is None else \ + (np.array(hkil),np.array([[1,0,0,0], + [0,1,0,0], + [0,0,0,1]])) + return np.einsum('il,...l->...i',basis,axis) + + + @classmethod + def Miller_to_Bravais(cls,uvw=None,hkl=None): + """ + Transform 3 Miller indices to 4 Miller–Bravais indices of crystal direction [uvtw] or plane normal (hkil). + + Parameters + ---------- + uvw | hkl : numpy.ndarray of shape (...,3) + Miller indices of crystallographic direction [uvw] or plane normal (hkl). + + Returns + ------- + uvtw | hkil : numpy.ndarray of shape (...,4) + Miller–Bravais indices of [uvtw] direction or (hkil) plane normal. + + """ + if (uvw is not None) ^ (hkl is None): + raise KeyError('Specify either "uvw" or "hkl"') + axis,basis = (np.array(uvw),np.array([[ 2,-1, 0], + [-1, 2, 0], + [-1,-1, 0], + [ 0, 0, 3]])/3) \ + if hkl is None else \ + (np.array(hkl),np.array([[ 1, 0, 0], + [ 0, 1, 0], + [-1,-1, 0], + [ 0, 0, 1]])) + return np.einsum('il,...l->...i',basis,axis) + + + def to_lattice(self,direction=None,plane=None): + """ + Calculate lattice vector corresponding to crystal frame direction or plane normal. + + Parameters + ---------- + direction | normal : numpy.ndarray of shape (...,3) + Vector along direction or plane normal. + + Returns + ------- + Miller : numpy.ndarray of shape (...,3) + lattice vector of direction or plane. + Use util.scale_to_coprime to convert to (integer) Miller indices. + + """ + if (direction is not None) ^ (plane is None): + raise KeyError('Specify either "direction" or "plane"') + axis,basis = (np.array(direction),self.basis_reciprocal.T) \ + if plane is None else \ + (np.array(plane),self.basis_real.T) + return np.einsum('il,...l->...i',basis,axis) + + + def to_frame(self,uvw=None,hkl=None,with_symmetry=False): + """ + Calculate crystal frame vector along lattice direction [uvw] or plane normal (hkl). + + Parameters + ---------- + uvw | hkl : numpy.ndarray of shape (...,3) + Miller indices of crystallographic direction or plane normal. + with_symmetry : bool, optional + Calculate all N symmetrically equivalent vectors. + + Returns + ------- + vector : numpy.ndarray of shape (...,3) or (N,...,3) + Crystal frame vector (or vectors if with_symmetry) along [uvw] direction or (hkl) plane normal. + + """ + if (uvw is not None) ^ (hkl is None): + raise KeyError('Specify either "uvw" or "hkl"') + axis,basis = (np.array(uvw),self.basis_real) \ + if hkl is None else \ + (np.array(hkl),self.basis_reciprocal) + return (self.symmetry_operations.broadcast_to(self.symmetry_operations.shape+axis.shape[:-1],mode='right') + @ np.broadcast_to(np.einsum('il,...l->...i',basis,axis),self.symmetry_operations.shape+axis.shape) + if with_symmetry else + np.einsum('il,...l->...i',basis,axis)) + + + def to_pole(self,uvw=None,hkl=None,with_symmetry=False): + """ + Calculate lab frame vector along lattice direction [uvw] or plane normal (hkl). + + Parameters + ---------- + uvw | hkl : numpy.ndarray of shape (...,3) + Miller indices of crystallographic direction or plane normal. + with_symmetry : bool, optional + Calculate all N symmetrically equivalent vectors. + + Returns + ------- + vector : numpy.ndarray of shape (...,3) or (N,...,3) + Lab frame vector (or vectors if with_symmetry) along [uvw] direction or (hkl) plane normal. + + """ + v = self.to_frame(uvw=uvw,hkl=hkl,with_symmetry=with_symmetry) + return ~(self if self.shape+v.shape[:-1] == () else self.broadcast_to(self.shape+v.shape[:-1],mode='right')) \ + @ np.broadcast_to(v,self.shape+v.shape) + + + def Schmid(self,mode): + u""" + Calculate Schmid matrix P = d ⨂ n in the lab frame for given lattice shear kinematics. + + Parameters + ---------- + mode : str + Type of kinematics, e.g. 'slip' or 'twin'. + + Returns + ------- + P : numpy.ndarray of shape (...,N,3,3) + Schmid matrix for each of the N deformation systems. + + """ + d = self.to_frame(uvw=self.kinematics[mode]['direction'],with_symmetry=False) + p = self.to_frame(hkl=self.kinematics[mode]['plane'] ,with_symmetry=False) + P = np.einsum('...i,...j->...ij',d/np.linalg.norm(d,axis=-1,keepdims=True), + p/np.linalg.norm(p,axis=-1,keepdims=True)) + + return ~self.broadcast_to( self.shape+P.shape[:-2],mode='right') \ + @ np.broadcast_to(P,self.shape+P.shape) diff --git a/python/damask/_result.py b/python/damask/_result.py index 3f4ca735c..5bed4347f 100644 --- a/python/damask/_result.py +++ b/python/damask/_result.py @@ -15,12 +15,12 @@ from numpy.lib import recfunctions as rfn import damask from . import VTK from . import Table -from . import Rotation from . import Orientation from . import grid_filters from . import mechanics from . import util +h5py3 = h5py.__version__[0] == '3' class Result: """ @@ -93,7 +93,7 @@ class Result: def __repr__(self): - """Show selected data.""" + """Show summary of file content.""" all_selected_increments = self.selection['increments'] self.pick('increments',all_selected_increments[0:1]) @@ -280,7 +280,8 @@ class Result: for path_old in self.get_dataset_location(name_old): path_new = os.path.join(os.path.dirname(path_old),name_new) f[path_new] = f[path_old] - f[path_new].attrs['Renamed'] = 'Original name: {}'.encode() + f[path_new].attrs['Renamed'] = f'Original name: {name_old}' if h5py3 else \ + f'Original name: {name_old}'.encode() del f[path_old] else: raise PermissionError('Rename operation not permitted') @@ -422,8 +423,13 @@ class Result: for d in f[group].keys(): try: dataset = f['/'.join([group,d])] - unit = f" / {dataset.attrs['Unit'].decode()}" if 'Unit' in dataset.attrs else '' - description = dataset.attrs['Description'].decode() + if 'Unit' in dataset.attrs: + unit = f" / {dataset.attrs['Unit']}" if h5py3 else \ + f" / {dataset.attrs['Unit'].decode()}" + else: + unit = '' + description = dataset.attrs['Description'] if h5py3 else \ + dataset.attrs['Description'].decode() message += f' {d}{unit}: {description}\n' except KeyError: pass @@ -463,7 +469,8 @@ class Result: def get_crystal_structure(self): # ToDo: extension to multi constituents/phase """Info about the crystal structure.""" with h5py.File(self.fname,'r') as f: - return f[self.get_dataset_location('orientation')[0]].attrs['Lattice'].astype('str') # np.bytes_ to string + return f[self.get_dataset_location('O')[0]].attrs['Lattice'] if h5py3 else \ + f[self.get_dataset_location('O')[0]].attrs['Lattice'].decode() def enable_user_function(self,func): @@ -735,11 +742,13 @@ class Result: def _add_IPF_color(q,l): m = util.scale_to_coprime(np.array(l)) - o = Orientation(Rotation(rfn.structured_to_unstructured(q['data'])), - lattice = q['meta']['Lattice']) + o = Orientation(rotation = (rfn.structured_to_unstructured(q['data'])), + lattice = {'fcc':'cF', + 'bcc':'cI', + 'hex':'hP'}[q['meta']['Lattice']]) return { - 'data': np.uint8(o.IPF_color(l)*255), + 'data': np.uint8(o.IPF_color(o.to_SST(l))*255), 'label': 'IPFcolor_[{} {} {}]'.format(*m), 'meta' : { 'Unit': '8-bit RGB', @@ -788,20 +797,26 @@ class Result: @staticmethod - def _add_Mises(T_sym): - t = 'strain' if T_sym['meta']['Unit'] == '1' else \ - 'stress' + def _add_Mises(T_sym,kind): + k = kind + if k is None: + if T_sym['meta']['Unit'] == '1': + k = 'strain' + elif T_sym['meta']['Unit'] == 'Pa': + k = 'stress' + if k not in ['stress', 'strain']: + raise ValueError('invalid von Mises kind {kind}') return { - 'data': (mechanics.Mises_strain if t=='strain' else mechanics.Mises_stress)(T_sym['data']), + 'data': (mechanics.Mises_strain if k=='strain' else mechanics.Mises_stress)(T_sym['data']), 'label': f"{T_sym['label']}_vM", 'meta': { 'Unit': T_sym['meta']['Unit'], - 'Description': f"Mises equivalent {t} of {T_sym['label']} ({T_sym['meta']['Description']})", + 'Description': f"Mises equivalent {k} of {T_sym['label']} ({T_sym['meta']['Description']})", 'Creator': 'add_Mises' } } - def add_Mises(self,T_sym): + def add_Mises(self,T_sym,kind=None): """ Add the equivalent Mises stress or strain of a symmetric tensor. @@ -809,9 +824,12 @@ class Result: ---------- T_sym : str Label of symmetric tensorial stress or strain dataset. + kind : {'stress', 'strain', None}, optional + Kind of the von Mises equivalent. Defaults to None, in which case + it is selected based on the unit of the dataset ('1' -> strain, 'Pa' -> stress'). """ - self._add_generic_pointwise(self._add_Mises,{'T_sym':T_sym}) + self._add_generic_pointwise(self._add_Mises,{'T_sym':T_sym},{'kind':kind}) @staticmethod @@ -880,42 +898,47 @@ class Result: self._add_generic_pointwise(self._add_PK2,{'P':P,'F':F}) - @staticmethod - def _add_pole(q,p,polar): - pole = np.array(p) - unit_pole = pole/np.linalg.norm(pole) - m = util.scale_to_coprime(pole) - rot = Rotation(q['data'].view(np.double).reshape(-1,4)) +# The add_pole functionality needs discussion. +# The new Crystal object can perform such a calculation but the outcome depends on the lattice parameters +# as well as on whether a direction or plane is concerned (see the DAMASK_examples/pole_figure notebook). +# Below code appears to be too simplistic. - rotatedPole = rot @ np.broadcast_to(unit_pole,rot.shape+(3,)) # rotate pole according to crystal orientation - xy = rotatedPole[:,0:2]/(1.+abs(unit_pole[2])) # stereographic projection - coords = xy if not polar else \ - np.block([np.sqrt(xy[:,0:1]*xy[:,0:1]+xy[:,1:2]*xy[:,1:2]),np.arctan2(xy[:,1:2],xy[:,0:1])]) - return { - 'data': coords, - 'label': 'p^{}_[{} {} {})'.format(u'rφ' if polar else 'xy',*m), - 'meta' : { - 'Unit': '1', - 'Description': '{} coordinates of stereographic projection of pole (direction/plane) in crystal frame'\ - .format('Polar' if polar else 'Cartesian'), - 'Creator': 'add_pole' - } - } - def add_pole(self,q,p,polar=False): - """ - Add coordinates of stereographic projection of given pole in crystal frame. - - Parameters - ---------- - q : str - 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 + # def _add_pole(q,p,polar): + # pole = np.array(p) + # unit_pole = pole/np.linalg.norm(pole) + # 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 + # xy = rotatedPole[:,0:2]/(1.+abs(unit_pole[2])) # stereographic projection + # coords = xy if not polar else \ + # np.block([np.sqrt(xy[:,0:1]*xy[:,0:1]+xy[:,1:2]*xy[:,1:2]),np.arctan2(xy[:,1:2],xy[:,0:1])]) + # return { + # 'data': coords, + # 'label': 'p^{}_[{} {} {})'.format(u'rφ' if polar else 'xy',*m), + # 'meta' : { + # 'Unit': '1', + # 'Description': '{} coordinates of stereographic projection of pole (direction/plane) in crystal frame'\ + # .format('Polar' if polar else 'Cartesian'), + # 'Creator': 'add_pole' + # } + # } + # def add_pole(self,q,p,polar=False): + # """ + # Add coordinates of stereographic projection of given pole in crystal frame. + # + # Parameters + # ---------- + # q : str + # 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 @@ -1035,7 +1058,7 @@ class Result: loc = f[group+'/'+label] datasets_in[arg]={'data' :loc[()], 'label':label, - 'meta': {k:v.decode() for k,v in loc.attrs.items()}} + 'meta': {k:(v if h5py3 else v.decode()) for k,v in loc.attrs.items()}} lock.release() r = func(**datasets_in,**args) return [group,r] @@ -1080,17 +1103,21 @@ class Result: if self._allow_modification and result[0]+'/'+result[1]['label'] in f: dataset = f[result[0]+'/'+result[1]['label']] dataset[...] = result[1]['data'] - dataset.attrs['Overwritten'] = 'Yes'.encode() + dataset.attrs['Overwritten'] = 'Yes' if h5py3 else \ + 'Yes'.encode() else: dataset = f[result[0]].create_dataset(result[1]['label'],data=result[1]['data']) now = datetime.datetime.now().astimezone() - dataset.attrs['Created'] = now.strftime('%Y-%m-%d %H:%M:%S%z').encode() + dataset.attrs['Created'] = now.strftime('%Y-%m-%d %H:%M:%S%z') if h5py3 else \ + now.strftime('%Y-%m-%d %H:%M:%S%z').encode() for l,v in result[1]['meta'].items(): - dataset.attrs[l]=v.encode() - creator = f"damask.Result.{dataset.attrs['Creator'].decode()} v{damask.version}" - dataset.attrs['Creator'] = creator.encode() + dataset.attrs[l]=v if h5py3 else v.encode() + creator = dataset.attrs['Creator'] if h5py3 else \ + dataset.attrs['Creator'].decode() + dataset.attrs['Creator'] = f"damask.Result.{creator} v{damask.version}" if h5py3 else \ + f"damask.Result.{creator} v{damask.version}".encode() except (OSError,RuntimeError) as err: print(f'Could not add dataset: {err}.') diff --git a/python/damask/_rotation.py b/python/damask/_rotation.py index b0c9dab5b..deae8b6ac 100644 --- a/python/damask/_rotation.py +++ b/python/damask/_rotation.py @@ -13,18 +13,18 @@ _R1 = (3.*np.pi/4.)**(1./3.) class Rotation: u""" - Orientation stored with functionality for conversion to different representations. + Rotation with functionality for conversion between different representations. The following conventions apply: - - coordinate frames are right-handed. - - a rotation angle ω is taken to be positive for a counterclockwise rotation + - Coordinate frames are right-handed. + - 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. - - 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, - with the angular ranges as [0,2π], [0,π], [0,2π]. - - the rotation angle ω is limited to the interval [0,π]. - - the real part of a quaternion is positive, Re(q) > 0 + with angular ranges of [0,2π], [0,π], [0,2π]. + - The rotation angle ω is limited to the interval [0,π]. + - The real part of a quaternion is positive, Re(q) > 0 - P = -1 (as default). Examples @@ -33,7 +33,7 @@ class Rotation: coordinates "b" expressed in system "B": - b = Q @ a - - b = np.dot(Q.asMatrix(),a) + - b = np.dot(Q.as_matrix(),a) References ---------- @@ -44,20 +44,83 @@ class Rotation: __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 ---------- - quaternion : numpy.ndarray, optional + rotation : list, numpy.ndarray, Rotation, optional Unit quaternion in positive real hemisphere. Use .from_quaternion to perform a sanity check. + Defaults to no rotation. """ - if quaternion.shape[-1] != 4: - raise ValueError('Not a quaternion') - self.quaternion = quaternion.copy() + if isinstance(rotation,Rotation): + self.quaternion = rotation.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 @@ -65,39 +128,36 @@ class Rotation: 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): """Length of leading/leftmost dimension of Rotation array.""" return 0 if self.shape == () else self.shape[0] - def __matmul__(self, other): + 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): """ Rotation of vector, second or fourth order tensor, or rotation object. @@ -112,14 +172,14 @@ class Rotation: Rotated vector, second or fourth order tensor, or rotation object. """ - if isinstance(other, Rotation): + if isinstance(other,Rotation): q_m = self.quaternion[...,0:1] p_m = self.quaternion[...,1:] q_o = other.quaternion[...,0:1] p_o = other.quaternion[...,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) - return self.__class__(np.block([q,p]))._standardize() + return Rotation(np.block([q,p]))._standardize() elif isinstance(other,np.ndarray): if self.shape + (3,) == other.shape: @@ -146,27 +206,89 @@ class Rotation: def _standardize(self): - """Standardize (ensure positive real hemisphere).""" + """Standardize quaternion (ensure positive real hemisphere).""" self.quaternion[self.quaternion[...,0] < 0.0] *= -1 return self - def inverse(self): - """In-place inverse rotation (backward rotation).""" - self.quaternion[...,1:] *= -1 - return self - def __invert__(self): - """Inverse rotation (backward rotation).""" - return self.copy().inverse() + def append(self,other): + """Extend rotation array along first dimension with other array.""" + return self.copy(rotation=np.vstack((self.quaternion,other.quaternion))) - def inversed(self): - """Inverse rotation (backward rotation).""" - return ~ self + + def flatten(self,order = 'C'): + """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): """ - Get Misorientation. + Calculate misorientation from self to other Rotation. Parameters ---------- @@ -177,33 +299,6 @@ class Rotation: 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) @@ -326,20 +421,6 @@ class Rotation: """ 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 # relax the conventions. @@ -347,7 +428,7 @@ class Rotation: def from_quaternion(q, accept_homomorph = False, P = -1, - acceptHomomorph = None): # old name (for compatibility) + **kwargs): """ Initialize from quaternion. @@ -363,15 +444,13 @@ class Rotation: Convention used. Defaults to -1. """ - if acceptHomomorph is not None: - accept_homomorph = acceptHomomorph # for compatibility qu = np.array(q,dtype=float) if qu.shape[:-2:-1] != (4,): raise ValueError('Invalid shape.') if abs(P) != 1: raise ValueError('P ∉ {-1,1}') - if P == 1: qu[...,1:4] *= -1 + qu[...,1:4] *= -P if accept_homomorph: qu[qu[...,0] < 0.0] *= -1 else: @@ -384,7 +463,8 @@ class Rotation: @staticmethod def from_Eulers(phi, - degrees = False): + degrees = False, + **kwargs): """ Initialize from Bunge-Euler angles. @@ -411,7 +491,8 @@ class Rotation: def from_axis_angle(axis_angle, degrees = False, normalize = False, - P = -1): + P = -1, + **kwargs): """ Initialize from Axis angle pair. @@ -434,7 +515,7 @@ class Rotation: if abs(P) != 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 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): @@ -448,14 +529,15 @@ class Rotation: @staticmethod def from_basis(basis, orthonormal = True, - reciprocal = False): + reciprocal = False, + **kwargs): """ Initialize from lattice basis vectors. Parameters ---------- basis : numpy.ndarray of shape (...,3,3) - Three lattice basis vectors in three dimensions. + Three three-dimensional lattice basis vectors. orthonormal : boolean, optional Basis is strictly orthonormal, i.e. is free of stretch components. Defaults to True. reciprocal : boolean, optional @@ -463,7 +545,7 @@ class Rotation: """ om = np.array(basis,dtype=float) - if om.shape[:-3:-1] != (3,3): + if om.shape[-2:] != (3,3): raise ValueError('Invalid shape.') if reciprocal: @@ -482,7 +564,7 @@ class Rotation: return Rotation(Rotation._om2qu(om)) @staticmethod - def from_matrix(R): + def from_matrix(R,**kwargs): """ Initialize from rotation matrix. @@ -494,10 +576,40 @@ class Rotation: """ 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 def from_Rodrigues(rho, normalize = False, - P = -1): + P = -1, + **kwargs): """ Initialize from Rodrigues-Frank vector. @@ -518,7 +630,7 @@ class Rotation: if abs(P) != 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 np.any(ro[...,3] < 0.0): raise ValueError('Rodrigues vector rotation angle not positive.') @@ -529,7 +641,8 @@ class Rotation: @staticmethod def from_homochoric(h, - P = -1): + P = -1, + **kwargs): """ Initialize from homochoric vector. @@ -547,7 +660,7 @@ class Rotation: if abs(P) != 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): raise ValueError('Homochoric coordinate outside of the sphere.') @@ -556,7 +669,8 @@ class Rotation: @staticmethod def from_cubochoric(c, - P = -1): + P = -1, + **kwargs): """ Initialize from cubochoric vector. @@ -577,46 +691,15 @@ class Rotation: if np.abs(np.max(cu)) > np.pi**(2./3.) * 0.5+1e-9: raise ValueError('Cubochoric coordinate outside of the cube.') - ho = Rotation._cu2ho(cu) - if P == 1: ho *= -1 + ho = -P * Rotation._cu2ho(cu) return Rotation(Rotation._ho2qu(ho)) @staticmethod - def from_average(rotations,weights = None): - """ - Average rotation. - - 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): + def from_random(shape = None, + seed = None, + **kwargs): """ Draw random rotation. @@ -633,12 +716,7 @@ class Rotation: """ rng = np.random.default_rng(seed) - if shape is None: - r = rng.random(3) - elif hasattr(shape, '__iter__'): - r = rng.random(tuple(shape)+(3,)) - else: - r = rng.random((shape,3)) + r = rng.random(3 if shape is None else tuple(shape)+(3,) if hasattr(shape, '__iter__') else (shape,3)) A = np.sqrt(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.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() - - # for compatibility - __mul__ = __matmul__ + return Rotation(q if shape is None else q.reshape(r.shape[:-1]+(4,)))._standardize() @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. @@ -707,7 +788,12 @@ class Rotation: @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. @@ -738,7 +824,13 @@ class Rotation: @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. diff --git a/python/damask/_table.py b/python/damask/_table.py index dd8df97b0..e90650eea 100644 --- a/python/damask/_table.py +++ b/python/damask/_table.py @@ -175,7 +175,7 @@ class Table: @property def labels(self): - return list(self.shapes.keys()) + return list(self.shapes) def get(self,label): diff --git a/python/damask/_test.py b/python/damask/_test.py index 5cadc9dfe..000b76e0e 100644 --- a/python/damask/_test.py +++ b/python/damask/_test.py @@ -316,12 +316,6 @@ class Test: return self.compare_Array(refName,curName) - def compare_ArrayCurCur(self,cur0,cur1): - - cur0Name = self.fileInCurrent(cur0) - cur1Name = self.fileInCurrent(cur1) - return self.compare_Array(cur0Name,cur1Name) - def compare_Table(self,headings0,file0, headings1,file1, normHeadings='',normType=None, diff --git a/python/damask/_vtk.py b/python/damask/_vtk.py index 10f3b482b..942be4f1f 100644 --- a/python/damask/_vtk.py +++ b/python/damask/_vtk.py @@ -197,11 +197,10 @@ class VTK: elif isinstance(self.vtk_data,vtk.vtkPolyData): writer = vtk.vtkXMLPolyDataWriter() - default_ext = writer.GetDefaultFileExtension() + default_ext = '.'+writer.GetDefaultFileExtension() ext = Path(fname).suffix - if ext and ext != '.'+default_ext: - raise ValueError(f'Given extension "{ext}" does not match default ".{default_ext}"') - writer.SetFileName(str(Path(fname).with_suffix('.'+default_ext))) + writer.SetFileName(str(fname)+(default_ext if default_ext != ext else '')) + if compress: writer.SetCompressorTypeToZLib() else: diff --git a/python/damask/lattice.py b/python/damask/lattice.py new file mode 100644 index 000000000..768dc5ace --- /dev/null +++ b/python/damask/lattice.py @@ -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), + }, +} diff --git a/python/damask/util.py b/python/damask/util.py index 914c3951c..d02877f8f 100644 --- a/python/damask/util.py +++ b/python/damask/util.py @@ -3,6 +3,7 @@ import datetime import os import subprocess import shlex +import re import fractions from functools import reduce from optparse import Option @@ -20,10 +21,13 @@ __all__=[ 'execute', 'show_progress', 'scale_to_coprime', + 'project_stereographic', 'hybrid_IA', 'return_message', 'extendableOption', - 'execution_stamp' + 'execution_stamp', + 'shapeshifter', + 'shapeblender', ] #################################################################################################### @@ -182,6 +186,28 @@ def scale_to_coprime(v): 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): """Timestamp the execution of a (function within a) class.""" 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]] +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 #################################################################################################### diff --git a/python/tests/reference/ConfigMaterial/material.yaml b/python/tests/reference/ConfigMaterial/material.yaml index 97c6504bb..933e295b3 100644 --- a/python/tests/reference/ConfigMaterial/material.yaml +++ b/python/tests/reference/ConfigMaterial/material.yaml @@ -33,12 +33,12 @@ material: phase: Aluminum: - elasticity: {C_11: 106.75e9, C_12: 60.41e9, C_44: 28.34e9, type: hooke} - generic: - output: [F, P, Fe, Fp, Lp] - lattice: fcc + lattice: cF + mech: + output: [F, P, F_e, F_p, L_p] + elasticity: {C_11: 106.75e9, C_12: 60.41e9, C_44: 28.34e9, type: hooke} Steel: - elasticity: {C_11: 233.3e9, C_12: 135.5e9, C_44: 118.0e9, type: hooke} - generic: - output: [F, P, Fe, Fp, Lp] - lattice: bcc + lattice: cI + mech: + output: [F, P, F_e, F_p, L_p] + elasticity: {C_11: 233.3e9, C_12: 135.5e9, C_44: 118.0e9, type: hooke} diff --git a/python/tests/reference/Orientation/cF_Bain.txt b/python/tests/reference/Orientation/cF_Bain.txt new file mode 100644 index 000000000..876cf3888 --- /dev/null +++ b/python/tests/reference/Orientation/cF_Bain.txt @@ -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 diff --git a/python/tests/reference/Orientation/cF_GT.txt b/python/tests/reference/Orientation/cF_GT.txt new file mode 100644 index 000000000..cefae431a --- /dev/null +++ b/python/tests/reference/Orientation/cF_GT.txt @@ -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 diff --git a/python/tests/reference/Orientation/cF_GT_prime.txt b/python/tests/reference/Orientation/cF_GT_prime.txt new file mode 100644 index 000000000..44a9b25ec --- /dev/null +++ b/python/tests/reference/Orientation/cF_GT_prime.txt @@ -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 diff --git a/python/tests/reference/Orientation/cF_KS.txt b/python/tests/reference/Orientation/cF_KS.txt new file mode 100644 index 000000000..93fdcf07e --- /dev/null +++ b/python/tests/reference/Orientation/cF_KS.txt @@ -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 diff --git a/python/tests/reference/Orientation/cF_NW.txt b/python/tests/reference/Orientation/cF_NW.txt new file mode 100644 index 000000000..cc9c95a05 --- /dev/null +++ b/python/tests/reference/Orientation/cF_NW.txt @@ -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 diff --git a/python/tests/reference/Orientation/cF_Pitsch.txt b/python/tests/reference/Orientation/cF_Pitsch.txt new file mode 100644 index 000000000..aa0c32365 --- /dev/null +++ b/python/tests/reference/Orientation/cF_Pitsch.txt @@ -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 diff --git a/python/tests/reference/Orientation/cF_slip.txt b/python/tests/reference/Orientation/cF_slip.txt new file mode 100644 index 000000000..18aa03f24 --- /dev/null +++ b/python/tests/reference/Orientation/cF_slip.txt @@ -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 diff --git a/python/tests/reference/Orientation/cF_twin.txt b/python/tests/reference/Orientation/cF_twin.txt new file mode 100644 index 000000000..8b0961823 --- /dev/null +++ b/python/tests/reference/Orientation/cF_twin.txt @@ -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 diff --git a/python/tests/reference/Orientation/cI_Bain.txt b/python/tests/reference/Orientation/cI_Bain.txt new file mode 100644 index 000000000..e0bc4f6c7 --- /dev/null +++ b/python/tests/reference/Orientation/cI_Bain.txt @@ -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 diff --git a/python/tests/reference/Orientation/cI_GT.txt b/python/tests/reference/Orientation/cI_GT.txt new file mode 100644 index 000000000..5d5102698 --- /dev/null +++ b/python/tests/reference/Orientation/cI_GT.txt @@ -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 diff --git a/python/tests/reference/Orientation/cI_GT_prime.txt b/python/tests/reference/Orientation/cI_GT_prime.txt new file mode 100644 index 000000000..e398d3139 --- /dev/null +++ b/python/tests/reference/Orientation/cI_GT_prime.txt @@ -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 diff --git a/python/tests/reference/Orientation/cI_KS.txt b/python/tests/reference/Orientation/cI_KS.txt new file mode 100644 index 000000000..34b393358 --- /dev/null +++ b/python/tests/reference/Orientation/cI_KS.txt @@ -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 diff --git a/python/tests/reference/Orientation/cI_NW.txt b/python/tests/reference/Orientation/cI_NW.txt new file mode 100644 index 000000000..754c69bba --- /dev/null +++ b/python/tests/reference/Orientation/cI_NW.txt @@ -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 diff --git a/python/tests/reference/Orientation/cI_Pitsch.txt b/python/tests/reference/Orientation/cI_Pitsch.txt new file mode 100644 index 000000000..ef28bbb4d --- /dev/null +++ b/python/tests/reference/Orientation/cI_Pitsch.txt @@ -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 diff --git a/python/tests/reference/Orientation/cI_slip.txt b/python/tests/reference/Orientation/cI_slip.txt new file mode 100644 index 000000000..5401392c8 --- /dev/null +++ b/python/tests/reference/Orientation/cI_slip.txt @@ -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 diff --git a/python/tests/reference/Orientation/cI_twin.txt b/python/tests/reference/Orientation/cI_twin.txt new file mode 100644 index 000000000..accbd02d8 --- /dev/null +++ b/python/tests/reference/Orientation/cI_twin.txt @@ -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 diff --git a/python/tests/reference/Orientation/hP_slip.txt b/python/tests/reference/Orientation/hP_slip.txt new file mode 100644 index 000000000..a67eea150 --- /dev/null +++ b/python/tests/reference/Orientation/hP_slip.txt @@ -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 diff --git a/python/tests/reference/Orientation/hP_twin.txt b/python/tests/reference/Orientation/hP_twin.txt new file mode 100644 index 000000000..62ce6fdef --- /dev/null +++ b/python/tests/reference/Orientation/hP_twin.txt @@ -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 diff --git a/python/tests/reference/Orientation/unitcell_cubic_0_0_0.pdf b/python/tests/reference/Orientation/unitcell_cubic_0_0_0.pdf new file mode 100644 index 000000000..f8ed27163 Binary files /dev/null and b/python/tests/reference/Orientation/unitcell_cubic_0_0_0.pdf differ diff --git a/python/tests/reference/Orientation/unitcell_cubic_0_45_0.pdf b/python/tests/reference/Orientation/unitcell_cubic_0_45_0.pdf new file mode 100644 index 000000000..1ebbb10d3 Binary files /dev/null and b/python/tests/reference/Orientation/unitcell_cubic_0_45_0.pdf differ diff --git a/python/tests/reference/Orientation/unitcell_cubic_180_45_180.pdf b/python/tests/reference/Orientation/unitcell_cubic_180_45_180.pdf new file mode 100644 index 000000000..9ecb9f44b Binary files /dev/null and b/python/tests/reference/Orientation/unitcell_cubic_180_45_180.pdf differ diff --git a/python/tests/reference/Orientation/unitcell_cubic_45_0_0.pdf b/python/tests/reference/Orientation/unitcell_cubic_45_0_0.pdf new file mode 100644 index 000000000..433a01bb2 Binary files /dev/null and b/python/tests/reference/Orientation/unitcell_cubic_45_0_0.pdf differ diff --git a/python/tests/reference/Orientation/unitcell_cubic_90_45_270.pdf b/python/tests/reference/Orientation/unitcell_cubic_90_45_270.pdf new file mode 100644 index 000000000..46d32c470 Binary files /dev/null and b/python/tests/reference/Orientation/unitcell_cubic_90_45_270.pdf differ diff --git a/python/tests/reference/Result/12grains6x7x8_tensionY.hdf5 b/python/tests/reference/Result/12grains6x7x8_tensionY.hdf5 index 39c17fadb..6d9334d1e 100644 Binary files a/python/tests/reference/Result/12grains6x7x8_tensionY.hdf5 and b/python/tests/reference/Result/12grains6x7x8_tensionY.hdf5 differ diff --git a/python/tests/reference/Result/6grains6x7x8_single_phase_tensionY.hdf5 b/python/tests/reference/Result/6grains6x7x8_single_phase_tensionY.hdf5 index 7812f82e8..799005217 100644 Binary files a/python/tests/reference/Result/6grains6x7x8_single_phase_tensionY.hdf5 and b/python/tests/reference/Result/6grains6x7x8_single_phase_tensionY.hdf5 differ diff --git a/python/tests/reference/Result/material.config b/python/tests/reference/Result/material.config deleted file mode 100644 index 4820b1eed..000000000 --- a/python/tests/reference/Result/material.config +++ /dev/null @@ -1,126 +0,0 @@ - -[none] -mech none -ngrains 1 - - -[Grain1] -(gauss) phi1 358.98 Phi 65.62 phi2 24.48 -[Grain2] -(gauss) phi1 121.05 Phi 176.11 phi2 295.73 -[Grain3] -(gauss) phi1 43.79 Phi 113.76 phi2 345.90 -[Grain4] -(gauss) phi1 265.15 Phi 62.52 phi2 299.71 -[Grain5] -(gauss) phi1 221.23 Phi 26.54 phi2 207.05 -[Grain6] -(gauss) phi1 249.81 Phi 61.47 phi2 152.14 -[Grain7] -(gauss) phi1 332.45 Phi 99.16 phi2 345.34 -[Grain8] -(gauss) phi1 312.27 Phi 118.27 phi2 181.59 -[Grain9] -(gauss) phi1 303.10 Phi 48.21 phi2 358.03 -[Grain10] -(gauss) phi1 338.26 Phi 48.11 phi2 176.78 -[Grain11] -(gauss) phi1 115.17 Phi 56.54 phi2 223.84 -[Grain12] -(gauss) phi1 281.04 Phi 97.48 phi2 27.94 - - -[Grain1] -crystallite 1 -(constituent) phase 1 texture 1 fraction 1.0 -[Grain2] -crystallite 1 -(constituent) phase 1 texture 2 fraction 1.0 -[Grain3] -crystallite 1 -(constituent) phase 1 texture 3 fraction 1.0 -[Grain4] -crystallite 1 -(constituent) phase 1 texture 4 fraction 1.0 -[Grain5] -crystallite 1 -(constituent) phase 1 texture 5 fraction 1.0 -[Grain6] -crystallite 1 -(constituent) phase 1 texture 6 fraction 1.0 -[Grain7] -crystallite 1 -(constituent) phase 2 texture 7 fraction 1.0 -[Grain8] -crystallite 1 -(constituent) phase 2 texture 8 fraction 1.0 -[Grain9] -crystallite 1 -(constituent) phase 2 texture 9 fraction 1.0 -[Grain10] -crystallite 1 -(constituent) phase 2 texture 10 fraction 1.0 -[Grain11] -crystallite 1 -(constituent) phase 2 texture 11 fraction 1.0 -[Grain12] -crystallite 1 -(constituent) phase 2 texture 12 fraction 1.0 - - -[pheno_fcc] -elasticity hooke -plasticity phenopowerlaw - -(output) orientation # quaternion -(output) F # deformation gradient tensor -(output) Fe # elastic deformation gradient tensor -(output) Fp # plastic deformation gradient tensor -(output) P # first Piola-Kichhoff stress tensor -(output) Lp # plastic velocity gradient tensor - - -lattice_structure fcc -Nslip 12 # per family -Ntwin 0 # per family - -c11 106.75e9 -c12 60.41e9 -c44 28.34e9 - -gdot0_slip 0.001 -n_slip 20 -tau0_slip 31e6 # per family -tausat_slip 63e6 # per family -a_slip 2.25 -h0_slipslip 75e6 -interaction_slipslip 1 1 1.4 1.4 1.4 1.4 -atol_resistance 1 - -[pheno_bcc] -elasticity hooke -plasticity phenopowerlaw - -(output) orientation # quaternion -(output) F # deformation gradient tensor -(output) Fe # elastic deformation gradient tensor -(output) Fp # plastic deformation gradient tensor -(output) P # first Piola-Kichhoff stress tensor -(output) Lp # plastic velocity gradient tensor - - -lattice_structure bcc -Nslip 12 # per family - -c11 106.75e9 -c12 60.41e9 -c44 28.34e9 - -gdot0_slip 0.001 -n_slip 20 -tau0_slip 31e6 # per family -tausat_slip 63e6 # per family -a_slip 2.25 -h0_slipslip 75e6 -interaction_slipslip 1 1 1.4 1.4 1.4 1.4 -atol_resistance 1 diff --git a/python/tests/reference/Result/material.yaml b/python/tests/reference/Result/material.yaml new file mode 100644 index 000000000..cd9cbad2a --- /dev/null +++ b/python/tests/reference/Result/material.yaml @@ -0,0 +1,103 @@ +--- +homogenization: + SX: + N_constituents: 1 + mech: {type: none} + +phase: + pheno_fcc: + lattice: fcc + mech: + output: [F, P, F_e, F_p, L_p, O] + elasticity: {C_11: 106.75e9, C_12: 60.41e9, C_44: 28.34e9, type: hooke} + plasticity: + N_sl: [12] + a_sl: 2.25 + atol_xi: 1.0 + dot_gamma_0_sl: 0.001 + h_0_sl_sl: 75e6 + h_sl_sl: [1, 1, 1.4, 1.4, 1.4, 1.4] + n_sl: 20 + output: [xi_sl] + type: phenopowerlaw + xi_0_sl: [31e6] + xi_inf_sl: [63e6] + pheno_bcc: + lattice: bcc + mech: + output: [F, P, F_e, F_p, L_p, O] + elasticity: {C_11: 106.75e9, C_12: 60.41e9, C_44: 28.34e9, type: hooke} + plasticity: + N_sl: [12] + a_sl: 2.25 + atol_xi: 1.0 + dot_gamma_0_sl: 0.001 + h_0_sl_sl: 75e6 + h_sl_sl: [1, 1, 1.4, 1.4, 1.4, 1.4] + n_sl: 20 + output: [xi_sl] + type: phenopowerlaw + xi_0_sl: [31e6] + xi_inf_sl: [63e6] + +material: + - constituents: + - fraction: 1.0 + O: [0.8229200444892315, 0.5284940239127993, -0.11958598847729246, 0.17086795611292308] + phase: pheno_fcc + homogenization: SX + - constituents: + - fraction: 1.0 + O: [0.029934934533052786, -0.0463822071939717, 0.9983440440417412, 0.01617900728410769] + phase: pheno_fcc + homogenization: SX + - constituents: + - fraction: 1.0 + O: [0.5285808688806949, 0.7326575088838098, 0.4051997815944012, 0.1401013087924221] + phase: pheno_fcc + homogenization: SX + - constituents: + - fraction: 1.0 + O: [0.1839974517790312, 0.49550065903084944, -0.1541415483910751, -0.8347840545305227] + phase: pheno_fcc + homogenization: SX + - constituents: + - fraction: 1.0 + O: [0.8055693100147384, -0.22778497057116814, -0.028331746016454287, 0.5462320075864553] + phase: pheno_fcc + homogenization: SX + - constituents: + - fraction: 1.0 + O: [0.8025842700117737, -0.33640019337884963, -0.3847408071640489, 0.3076815085881779] + phase: pheno_fcc + homogenization: SX + - constituents: + - fraction: 1.0 + O: [0.6048933483394416, 0.7565005822419409, -0.08545681892422426, -0.2334695661144201] + phase: pheno_bcc + homogenization: SX + - constituents: + - fraction: 1.0 + O: [0.2012339360745425, -0.3580127491130033, -0.7798091137625135, 0.47247171400774884] + phase: pheno_bcc + homogenization: SX + - constituents: + - fraction: 1.0 + O: [0.7949688202267222, 0.3623793306926909, -0.18836147613310203, -0.4485819321629098] + phase: pheno_bcc + homogenization: SX + - constituents: + - fraction: 1.0 + O: [0.19733162113429173, -0.06559103894055797, -0.40230149937129567, 0.8915781236183501] + phase: pheno_bcc + homogenization: SX + - constituents: + - fraction: 1.0 + O: [0.8659916384140512, -0.2761459420825848, 0.38479354764225004, -0.1604238964779258] + phase: pheno_bcc + homogenization: SX + - constituents: + - fraction: 1.0 + O: [0.5951846978175659, 0.4476701545571293, -0.6038886363266418, -0.2840160613735736] + phase: pheno_bcc + homogenization: SX diff --git a/python/tests/reference/Result/tensionY.load b/python/tests/reference/Result/tensionY.load deleted file mode 100644 index 9332144d8..000000000 --- a/python/tests/reference/Result/tensionY.load +++ /dev/null @@ -1 +0,0 @@ -fdot * 0 0 0 1.0e-3 0 0 0 * stress 0 * * * * * * * 0 time 20 incs 40 freq 4 diff --git a/python/tests/reference/Result/tensionY.yaml b/python/tests/reference/Result/tensionY.yaml new file mode 100644 index 000000000..eb34e3e47 --- /dev/null +++ b/python/tests/reference/Result/tensionY.yaml @@ -0,0 +1,14 @@ +--- + +step: + - discretization: + t: 20 + N: 40 + f_out: 4 + mech: + dot_F: [x, 0, 0, + 0, 1.0e-3, 0, + 0, 0, x] + P: [0, x, x, + x, x, x, + x, x, 0] diff --git a/python/tests/test_Geom.py b/python/tests/test_Geom.py index 0d393a4c4..a9b9c91b5 100644 --- a/python/tests/test_Geom.py +++ b/python/tests/test_Geom.py @@ -6,6 +6,7 @@ from damask import Geom from damask import Table from damask import Rotation from damask import util +from damask import seeds from damask import grid_filters @@ -204,6 +205,11 @@ class TestGeom: assert np.array_equiv(t,f) or (not geom_equal(modified,default)) assert geom_equal(default, modified.substitute(t,f)) + def test_sort(self): + grid = np.random.randint(5,20,3) + m = Geom(np.random.randint(1,20,grid)*3,np.ones(3)).sort().material.flatten(order='F') + for i,v in enumerate(m): + assert i==0 or v > m[:i].max() or v in m[:i] @pytest.mark.parametrize('axis_angle',[np.array([1,0,0,86.7]), np.array([0,1,0,90.4]), np.array([0,0,1,90]), np.array([1,0,0,175]),np.array([0,-1,0,178]),np.array([0,0,1,180])]) @@ -259,12 +265,12 @@ class TestGeom: @pytest.mark.parametrize('inverse',[True,False]) @pytest.mark.parametrize('periodic',[True,False]) def test_add_primitive_rotation(self,center,inverse,periodic): - """Rotation should not change result for sphere (except for discretization errors).""" - g = np.array([32,32,32]) + """Rotation should not change result for sphere.""" + g = np.random.randint(8,32,(3)) + s = np.random.random(3)+.5 fill = np.random.randint(10)+2 - eu=np.array([np.random.randint(4),np.random.randint(2),np.random.randint(4)])*.5*np.pi - G_1 = Geom(np.ones(g,'i'),[1.,1.,1.]).add_primitive(.3,center,1,fill,inverse=inverse,periodic=periodic) - G_2 = Geom(np.ones(g,'i'),[1.,1.,1.]).add_primitive(.3,center,1,fill,Rotation.from_Eulers(eu),inverse,periodic=periodic) + G_1 = Geom(np.ones(g,'i'),s).add_primitive(.3,center,1,fill,inverse=inverse,periodic=periodic) + G_2 = Geom(np.ones(g,'i'),s).add_primitive(.3,center,1,fill,Rotation.from_random(),inverse,periodic=periodic) assert geom_equal(G_1,G_2) @@ -384,3 +390,13 @@ class TestGeom: t = Table(np.column_stack((coords,z)),{'coords':3,'z':1}) g = Geom.from_table(t,'coords',['1_coords','z']) assert g.N_materials == g.grid[0]*2 and (g.material[:,:,-1]-g.material[:,:,0] == grid[0]).all() + + + def test_from_table_recover(self,tmp_path): + grid = np.random.randint(60,100,3) + size = np.ones(3)+np.random.rand(3) + s = seeds.from_random(size,np.random.randint(60,100)) + geom = Geom.from_Voronoi_tessellation(grid,size,s) + coords = grid_filters.cell_coord0(grid,size) + t = Table(np.column_stack((coords.reshape(-1,3,order='F'),geom.material.flatten(order='F'))),{'c':3,'m':1}) + assert geom_equal(geom.sort().renumber(),Geom.from_table(t,'c',['m'])) diff --git a/python/tests/test_Lattice.py b/python/tests/test_Lattice.py deleted file mode 100644 index 93fc56445..000000000 --- a/python/tests/test_Lattice.py +++ /dev/null @@ -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))') diff --git a/python/tests/test_Orientation.py b/python/tests/test_Orientation.py index 669f73e91..fe35bda14 100644 --- a/python/tests/test_Orientation.py +++ b/python/tests/test_Orientation.py @@ -1,131 +1,536 @@ -import os -from itertools import permutations - import pytest import numpy as np +from itertools import permutations -from damask import Table from damask import Rotation from damask import Orientation -from damask import Lattice - -n = 1000 - -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) +from damask import Table +from damask import lattice +from damask import util @pytest.fixture def reference_dir(reference_dir_base): """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: - @pytest.mark.parametrize('model',['Bain','KS','GT','GT_prime','NW','Pitsch']) - @pytest.mark.parametrize('lattice',['fcc','bcc']) - def test_relationship_vectorize(self,set_of_quaternions,lattice,model): - result = Orientation(set_of_quaternions[:200].reshape(50,4,4),lattice).related(model) - ref_qu = result.rotation.quaternion.reshape(-1,200,4) - 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',Orientation.crystal_families) + @pytest.mark.parametrize('shape',[None,5,(4,6)]) + def test_equal(self,lattice,shape): + R = Rotation.from_random(shape) + assert Orientation(R,lattice) == Orientation(R,lattice) - @pytest.mark.parametrize('lattice',Lattice.lattices) - def test_IPF_vectorize(self,set_of_quaternions,lattice): - direction = np.random.random(3)*2.0-1 - oris = Orientation(Rotation(set_of_quaternions),lattice)[:200] - for i,color in enumerate(oris.IPF_color(direction)): - assert np.allclose(color,IPF_color(oris[i],direction)) + @pytest.mark.parametrize('lattice',Orientation.crystal_families) + @pytest.mark.parametrize('shape',[None,5,(4,6)]) + def test_unequal(self,lattice,shape): + R = Rotation.from_random(shape) + assert not(Orientation(R,lattice) != Orientation(R,lattice)) - @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('lattice',Lattice.lattices) - def test_inverse_pole_vectorize(self,set_of_quaternions,lattice,SST,proper): - axis = np.random.random(3)*2.0-1 - oris = Orientation(Rotation(set_of_quaternions),lattice)[:200] - for i,pole in enumerate(oris.inverse_pole(axis,SST=SST)): - assert np.allclose(pole,inverse_pole(oris[i],axis,SST=SST)) + def test_to_SST_vectorization(self,lattice,shape,vector,proper): + o = Orientation.from_random(lattice=lattice,shape=shape,seed=0) + for r, theO in zip(o.to_SST(vector=vector,proper=proper).reshape((-1,3)),o.flatten()): + assert np.allclose(r,theO.to_SST(vector=vector,proper=proper)) + + @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]}, {'label':'green','RGB':[0,1,0],'direction':[0,1,1]}, {'label':'blue', 'RGB':[0,0,1],'direction':[1,1,1]}]) - @pytest.mark.parametrize('lattice',['fcc','bcc']) - def test_IPF_cubic(self,color,lattice): - cube = Orientation(Rotation(),lattice) + @pytest.mark.parametrize('proper',[True,False]) + def test_IPF_cubic(self,color,proper): + cube = Orientation(lattice='cubic') 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) - def test_IPF_equivalent(self,set_of_quaternions,lattice): - direction = np.random.random(3)*2.0-1 - for ori in Orientation(Rotation(set_of_quaternions),lattice)[:200]: - color = ori.IPF_color(direction) - for equivalent in ori.equivalent: - assert np.allclose(color,equivalent.IPF_color(direction)) + @pytest.mark.parametrize('lattice',Orientation.crystal_families) + @pytest.mark.parametrize('proper',[True,False]) + def test_IPF_equivalent(self,set_of_quaternions,lattice,proper): + direction = np.random.random(3)*2.0-1.0 + o = Orientation(rotation=set_of_quaternions,lattice=lattice).equivalent + color = o.IPF_color(o.to_SST(vector=direction,proper=proper),proper=proper) + assert np.allclose(np.broadcast_to(color[0,...],color.shape),color) - @pytest.mark.parametrize('lattice',Lattice.lattices) - def test_reduced(self,set_of_quaternions,lattice): - oris = Orientation(Rotation(set_of_quaternions),lattice) - reduced = oris.reduced - assert np.all(reduced.in_FZ) and oris.rotation.shape == reduced.rotation.shape + @pytest.mark.parametrize('lattice',Orientation.crystal_families) + def test_in_FZ_vectorization(self,set_of_rodrigues,lattice): + result = Orientation.from_Rodrigues(rho=set_of_rodrigues.reshape((50,4,-1)),lattice=lattice).in_FZ.reshape(-1) + for r,rho in zip(result,set_of_rodrigues[:len(result)]): + 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('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): - ori = Orientation(Rotation.from_random(),lattice) - for i,r in enumerate(ori.related(model)): - ori2 = r.related(model)[i] - misorientation = ori.rotation.misorientation(ori2.rotation) - assert misorientation.as_axis_angle(degrees=True)[3]<1.0e-5 + o = Orientation.from_random(lattice=lattice) + for i,r in enumerate(o.related(model)): + assert o.disorientation(r.related(model)[i]).as_axis_angle(degrees=True,pair=True)[1]<1.0e-5 @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): - reference = os.path.join(reference_dir,f'{lattice}_{model}.txt') - ori = Orientation(Rotation(),lattice) - eu = np.array([o.rotation.as_Eulers(degrees=True) for o in ori.related(model)]) + reference = reference_dir/f'{lattice}_{model}.txt' + o = Orientation(lattice=lattice) + eu = o.related(model).as_Eulers(degrees=True) if update: coords = np.array([(1,i+1) for i,x in enumerate(eu)]) - table = Table(eu,{'Eulers':(3,)}) - table = table.add('pos',coords) - table.save(reference) + Table(eu,{'Eulers':(3,)})\ + .add('pos',coords)\ + .save(reference) assert np.allclose(eu,Table.load(reference).get('Eulers')) - @pytest.mark.parametrize('lattice',Lattice.lattices) - def test_disorientation360(self,lattice): - R_1 = Orientation(Rotation(),lattice) - R_2 = Orientation(Rotation.from_Eulers([360,0,0],degrees=True),lattice) - assert np.allclose(R_1.disorientation(R_2).as_matrix(),np.eye(3)) + def test_basis_real(self): + for gamma in np.random.random(2**8)*np.pi: + basis = np.tril(np.random.random((3,3))+1e-6) + basis[1,:2] = basis[1,1]*np.array([np.cos(gamma),np.sin(gamma)]) + 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('angle',[10,20,30,40]) - def test_average(self,angle,lattice): - R_1 = Orientation(Rotation.from_axis_angle([0,0,1,10],degrees=True),lattice) - R_2 = Orientation(Rotation.from_axis_angle([0,0,1,angle],degrees=True),lattice) - avg_angle = R_1.average(R_2).rotation.as_axis_angle(degrees=True,pair=True)[1] - assert np.isclose(avg_angle,10+(angle-10)/2.) + @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,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) - def test_from_average(self,lattice): - R_1 = Orientation(Rotation.from_random(),lattice) - eqs = [r for r in R_1.equivalent] - R_2 = Orientation.from_average(eqs) - assert np.allclose(R_1.rotation.quaternion,R_2.rotation.quaternion) + @pytest.mark.parametrize('keyFrame,keyLattice',[('uvw','direction'),('hkl','plane'),]) + @pytest.mark.parametrize('vector',np.array([ + [1.,1.,1.], + [-2.,3.,0.5], + [0.,0.,1.], + [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')) diff --git a/python/tests/test_Result.py b/python/tests/test_Result.py index 5ef17cd26..929c0ef44 100644 --- a/python/tests/test_Result.py +++ b/python/tests/test_Result.py @@ -94,11 +94,11 @@ class TestResult: default.pick('invalid',True) def test_add_absolute(self,default): - default.add_absolute('Fe') - loc = {'Fe': default.get_dataset_location('Fe'), - '|Fe|': default.get_dataset_location('|Fe|')} - in_memory = np.abs(default.read_dataset(loc['Fe'],0)) - in_file = default.read_dataset(loc['|Fe|'],0) + default.add_absolute('F_e') + loc = {'F_e': default.get_dataset_location('F_e'), + '|F_e|': default.get_dataset_location('|F_e|')} + in_memory = np.abs(default.read_dataset(loc['F_e'],0)) + in_file = default.read_dataset(loc['|F_e|'],0) assert np.allclose(in_memory,in_file) @pytest.mark.parametrize('mode',['direct','function']) @@ -168,15 +168,16 @@ class TestResult: @pytest.mark.parametrize('d',[[1,0,0],[0,1,0],[0,0,1]]) def test_add_IPF_color(self,default,d): - default.add_IPF_color('orientation',d) - loc = {'orientation': default.get_dataset_location('orientation'), - 'color': default.get_dataset_location('IPFcolor_[{} {} {}]'.format(*d))} - qu = default.read_dataset(loc['orientation']).view(np.double).reshape(-1,4) + default.add_IPF_color('O',np.array(d)) + loc = {'O': default.get_dataset_location('O'), + 'color': default.get_dataset_location('IPFcolor_[{} {} {}]'.format(*d))} + qu = default.read_dataset(loc['O']).view(np.double).squeeze() crystal_structure = default.get_crystal_structure() - in_memory = np.empty((qu.shape[0],3),np.uint8) - for i,q in enumerate(qu): - o = Orientation(q,crystal_structure).reduced - in_memory[i] = np.uint8(o.IPF_color(np.array(d))*255) + c = Orientation(rotation=qu, + lattice={'fcc':'cF', + 'bcc':'cI', + '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']) assert np.allclose(in_memory,in_file) @@ -209,6 +210,22 @@ class TestResult: in_memory = mechanics.Mises_stress(default.read_dataset(loc['sigma'],0)).reshape(-1,1) in_file = default.read_dataset(loc['sigma_vM'],0) assert np.allclose(in_memory,in_file) + + def test_add_Mises_invalid(self,default): + default.add_Cauchy('P','F') + default.add_calculation('sigma_y','#sigma#',unit='y') + default.add_Mises('sigma_y') + assert default.get_dataset_location('sigma_y_vM') == [] + + def test_add_Mises_stress_strain(self,default): + default.add_Cauchy('P','F') + default.add_calculation('sigma_y','#sigma#',unit='y') + default.add_calculation('sigma_x','#sigma#',unit='x') + default.add_Mises('sigma_y',kind='strain') + default.add_Mises('sigma_x',kind='stress') + loc = {'y' :default.get_dataset_location('sigma_y_vM'), + 'x' :default.get_dataset_location('sigma_x_vM')} + assert not np.allclose(default.read_dataset(loc['y'],0),default.read_dataset(loc['x'],0)) def test_add_norm(self,default): default.add_norm('F',1) @@ -228,13 +245,14 @@ class TestResult: in_file = default.read_dataset(loc['S'],0) assert np.allclose(in_memory,in_file) + @pytest.mark.skip(reason='requires rework of lattice.f90') @pytest.mark.parametrize('polar',[True,False]) def test_add_pole(self,default,polar): pole = np.array([1.,0.,0.]) - default.add_pole('orientation',pole,polar) - loc = {'orientation': default.get_dataset_location('orientation'), - '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)) + default.add_pole('O',pole,polar) + loc = {'O': default.get_dataset_location('O'), + 'pole': default.get_dataset_location('p^{}_[1 0 0)'.format(u'rφ' if polar else 'xy'))} + rot = Rotation(default.read_dataset(loc['O']).view(np.double)) rotated_pole = rot * np.broadcast_to(pole,rot.shape+(3,)) xy = rotated_pole[:,0:2]/(1.+abs(pole[2])) in_memory = xy if not polar else \ @@ -296,7 +314,11 @@ class TestResult: default.add_Cauchy() loc = default.get_dataset_location('sigma') with h5py.File(default.fname,'r') as f: - created_first = f[loc[0]].attrs['Created'].decode() + # h5py3 compatibility + try: + created_first = f[loc[0]].attrs['Created'].decode() + except AttributeError: + created_first = f[loc[0]].attrs['Created'] created_first = datetime.strptime(created_first,'%Y-%m-%d %H:%M:%S%z') if overwrite == 'on': @@ -305,9 +327,16 @@ class TestResult: default.disallow_modification() time.sleep(2.) - default.add_calculation('sigma','#sigma#*0.0+311.','not the Cauchy stress') + try: + default.add_calculation('sigma','#sigma#*0.0+311.','not the Cauchy stress') + except ValueError: + pass with h5py.File(default.fname,'r') as f: - created_second = f[loc[0]].attrs['Created'].decode() + # h5py3 compatibility + try: + created_second = f[loc[0]].attrs['Created'].decode() + except AttributeError: + created_second = f[loc[0]].attrs['Created'] created_second = datetime.strptime(created_second,'%Y-%m-%d %H:%M:%S%z') if overwrite == 'on': assert created_first < created_second and np.allclose(default.read_dataset(loc),311.) diff --git a/python/tests/test_Rotation.py b/python/tests/test_Rotation.py index d70d650a0..9361008e5 100644 --- a/python/tests/test_Rotation.py +++ b/python/tests/test_Rotation.py @@ -771,6 +771,53 @@ class TestRotation: def test_random(self,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, Rotation.from_Eulers, Rotation.from_axis_angle, @@ -848,7 +895,8 @@ class TestRotation: np.random.rand(3,3,3,3)]) def test_rotate_identity(self,data): 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), np.random.rand(3,3), @@ -860,6 +908,16 @@ class TestRotation: R_2 = Rotation.from_Eulers(np.array([0.,0.,phi_2])) 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): R = Rotation.from_random() assert np.allclose(np.eye(3),(~R@R).as_matrix()) @@ -877,7 +935,7 @@ class TestRotation: def test_rotate_invalid_shape(self,data): R = Rotation.from_random() with pytest.raises(ValueError): - R*data + R@data @pytest.mark.parametrize('data',['does_not_work', (1,2), @@ -885,7 +943,7 @@ class TestRotation: def test_rotate_invalid_type(self,data): R = Rotation.from_random() with pytest.raises(TypeError): - R*data + R@data def test_misorientation(self): 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]) def test_average(self,angle): - R_1 = Rotation.from_axis_angle([0,0,1,10],degrees=True) - R_2 = Rotation.from_axis_angle([0,0,1,angle],degrees=True) - avg_angle = R_1.average(R_2).as_axis_angle(degrees=True,pair=True)[1] + R = Rotation.from_axis_angle([[0,0,1,10],[0,0,1,angle]],degrees=True) + avg_angle = R.average().as_axis_angle(degrees=True,pair=True)[1] assert np.isclose(avg_angle,10+(angle-10)/2.) diff --git a/python/tests/test_VTK.py b/python/tests/test_VTK.py index 63adb6454..bab6051b0 100644 --- a/python/tests/test_VTK.py +++ b/python/tests/test_VTK.py @@ -85,6 +85,12 @@ class TestVTK: assert(False) + @pytest.mark.parametrize('fname',['a','a.vtp','a.b','a.b.vtp']) + def test_filename_variations(self,tmp_path,fname): + points = np.random.rand(102,3) + v = VTK.from_poly_data(points) + v.save(tmp_path/fname) + @pytest.mark.parametrize('name,dataset_type',[('this_file_does_not_exist.vtk', None), ('this_file_does_not_exist.vtk','vtk'), ('this_file_does_not_exist.vtx', None)]) @@ -92,9 +98,10 @@ class TestVTK: with pytest.raises(TypeError): VTK.load(name,dataset_type) - def test_invalid_extension_write(self,default): - with pytest.raises(ValueError): - default.save('default.txt') + def test_add_extension(self,tmp_path,default): + default.save(tmp_path/'default.txt',parallel=False) + assert os.path.isfile(tmp_path/'default.txt.vtr') + def test_invalid_get(self,default): with pytest.raises(ValueError): diff --git a/python/tests/test_util.py b/python/tests/test_util.py index 0b5593e8e..19b6377f6 100644 --- a/python/tests/test_util.py +++ b/python/tests/test_util.py @@ -44,3 +44,52 @@ class TestUtil: selected = util.hybrid_IA(dist,N_samples) 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 + + @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 diff --git a/src/HDF5_utilities.f90 b/src/HDF5_utilities.f90 index a13ac1a8a..47f4243e7 100644 --- a/src/HDF5_utilities.f90 +++ b/src/HDF5_utilities.f90 @@ -12,11 +12,10 @@ module HDF5_utilities use prec use parallelization - use IO use rotations - implicit none - public + implicit none + public !-------------------------------------------------------------------------------------------------- !> @brief reads integer or float data of defined shape from file ! ToDo: order of arguments wrong @@ -93,15 +92,15 @@ subroutine HDF5_utilities_init !-------------------------------------------------------------------------------------------------- !initialize HDF5 library and check if integer and float type size match call h5open_f(hdferr) - if (hdferr < 0) call IO_error(1,ext_msg='HDF5_Utilities_init: h5open_f') + if(hdferr < 0) error stop 'HDF5 error' call h5tget_size_f(H5T_NATIVE_INTEGER,typeSize, hdferr) - if (hdferr < 0) call IO_error(1,ext_msg='HDF5_Utilities_init: h5tget_size_f (int)') + if(hdferr < 0) error stop 'HDF5 error' if (int(bit_size(0),SIZE_T)/=typeSize*8) & error stop 'Default integer size does not match H5T_NATIVE_INTEGER' call h5tget_size_f(H5T_NATIVE_DOUBLE,typeSize, hdferr) - if (hdferr < 0) call IO_error(1,ext_msg='HDF5_Utilities_init: h5tget_size_f (double)') + if(hdferr < 0) error stop 'HDF5 error' if (int(storage_size(0.0_pReal),SIZE_T)/=typeSize*8) & error stop 'pReal does not match H5T_NATIVE_DOUBLE' @@ -128,30 +127,30 @@ integer(HID_T) function HDF5_openFile(fileName,mode,parallel) endif call h5pcreate_f(H5P_FILE_ACCESS_F, plist_id, hdferr) - if (hdferr < 0) call IO_error(1,ext_msg='HDF5_openFile: h5pcreate_f') + if(hdferr < 0) error stop 'HDF5 error' #ifdef PETSc if (present(parallel)) then; if (parallel) then call h5pset_fapl_mpio_f(plist_id, PETSC_COMM_WORLD, MPI_INFO_NULL, hdferr) - if (hdferr < 0) call IO_error(1,ext_msg='HDF5_openFile: h5pset_fapl_mpio_f') + if(hdferr < 0) error stop 'HDF5 error' endif; endif #endif if (m == 'w') then call h5fcreate_f(fileName,H5F_ACC_TRUNC_F,HDF5_openFile,hdferr,access_prp = plist_id) - if (hdferr < 0) call IO_error(1,ext_msg='HDF5_openFile: h5fcreate_f (w)') + if(hdferr < 0) error stop 'HDF5 error' elseif(m == 'a') then call h5fopen_f(fileName,H5F_ACC_RDWR_F,HDF5_openFile,hdferr,access_prp = plist_id) - if (hdferr < 0) call IO_error(1,ext_msg='HDF5_openFile: h5fopen_f (a)') + if(hdferr < 0) error stop 'HDF5 error' elseif(m == 'r') then call h5fopen_f(fileName,H5F_ACC_RDONLY_F,HDF5_openFile,hdferr,access_prp = plist_id) - if (hdferr < 0) call IO_error(1,ext_msg='HDF5_openFile: h5fopen_f (r)') + if(hdferr < 0) error stop 'HDF5 error' else - call IO_error(1,ext_msg='HDF5_openFile: h5fopen_f unknown access mode: '//trim(m)) + error stop 'unknown access mode' endif call h5pclose_f(plist_id, hdferr) - if (hdferr < 0) call IO_error(1,ext_msg='HDF5_openFile: h5pclose_f') + if(hdferr < 0) error stop 'HDF5 error' end function HDF5_openFile @@ -166,7 +165,7 @@ subroutine HDF5_closeFile(fileHandle) integer :: hdferr call h5fclose_f(fileHandle,hdferr) - if (hdferr < 0) call IO_error(1,ext_msg='HDF5_closeFile: h5fclose_f') + if(hdferr < 0) error stop 'HDF5 error' end subroutine HDF5_closeFile @@ -185,19 +184,19 @@ integer(HID_T) function HDF5_addGroup(fileHandle,groupName) !------------------------------------------------------------------------------------------------- ! creating a property list for data access properties call h5pcreate_f(H5P_GROUP_ACCESS_F, aplist_id, hdferr) - if (hdferr < 0) call IO_error(1,ext_msg = 'HDF5_addGroup: h5pcreate_f ('//trim(groupName)//')') + if(hdferr < 0) error stop 'HDF5 error' !------------------------------------------------------------------------------------------------- ! setting I/O mode to collective #ifdef PETSc call h5pset_all_coll_metadata_ops_f(aplist_id, .true., hdferr) - if (hdferr < 0) call IO_error(1,ext_msg = 'HDF5_addGroup: h5pset_all_coll_metadata_ops_f ('//trim(groupName)//')') + if(hdferr < 0) error stop 'HDF5 error' #endif !------------------------------------------------------------------------------------------------- ! Create group call h5gcreate_f(fileHandle, trim(groupName), HDF5_addGroup, hdferr, OBJECT_NAMELEN_DEFAULT_F,gapl_id = aplist_id) - if (hdferr < 0) call IO_error(1,ext_msg = 'HDF5_addGroup: h5gcreate_f ('//trim(groupName)//')') + if(hdferr < 0) error stop 'HDF5 error' call h5pclose_f(aplist_id,hdferr) @@ -221,19 +220,19 @@ integer(HID_T) function HDF5_openGroup(fileHandle,groupName) !------------------------------------------------------------------------------------------------- ! creating a property list for data access properties call h5pcreate_f(H5P_GROUP_ACCESS_F, aplist_id, hdferr) - if (hdferr < 0) call IO_error(1,ext_msg = 'HDF5_openGroup: h5pcreate_f ('//trim(groupName)//')') + if(hdferr < 0) error stop 'HDF5 error' !------------------------------------------------------------------------------------------------- ! setting I/O mode to collective #ifdef PETSc call h5pget_all_coll_metadata_ops_f(aplist_id, is_collective, hdferr) - if (hdferr < 0) call IO_error(1,ext_msg = 'HDF5_openGroup: h5pset_all_coll_metadata_ops_f ('//trim(groupName)//')') + if(hdferr < 0) error stop 'HDF5 error' #endif !------------------------------------------------------------------------------------------------- ! opening the group call h5gopen_f(fileHandle, trim(groupName), HDF5_openGroup, hdferr, gapl_id = aplist_id) - if (hdferr < 0) call IO_error(1,ext_msg = 'HDF5_openGroup: h5gopen_f ('//trim(groupName)//')') + if(hdferr < 0) error stop 'HDF5 error' call h5pclose_f(aplist_id,hdferr) @@ -250,7 +249,7 @@ subroutine HDF5_closeGroup(group_id) integer :: hdferr call h5gclose_f(group_id, hdferr) - if (hdferr < 0) call IO_error(1,ext_msg = 'HDF5_closeGroup: h5gclose_f (el is ID)', el = int(group_id)) + if(hdferr < 0) error stop 'HDF5 error' end subroutine HDF5_closeGroup @@ -273,11 +272,11 @@ logical function HDF5_objectExists(loc_id,path) endif call h5lexists_f(loc_id, p, HDF5_objectExists, hdferr) - if (hdferr < 0) call IO_error(1,ext_msg = 'HDF5_objectExists: h5oexists_by_name_f') + if(hdferr < 0) error stop 'HDF5 error' if(HDF5_objectExists) then call h5oexists_by_name_f(loc_id, p, HDF5_objectExists, hdferr) - if (hdferr < 0) call IO_error(1,ext_msg = 'HDF5_objectExists: h5oexists_by_name_f') + if(hdferr < 0) error stop 'HDF5 error' endif end function HDF5_objectExists @@ -296,6 +295,8 @@ subroutine HDF5_addAttribute_str(loc_id,attrLabel,attrValue,path) logical :: attrExists integer :: hdferr character(len=:), allocatable :: p + character(len=:,kind=C_CHAR), allocatable,target :: attrValue_ + type(c_ptr), target, dimension(1) :: ptr if (present(path)) then p = trim(path) @@ -303,28 +304,29 @@ subroutine HDF5_addAttribute_str(loc_id,attrLabel,attrValue,path) p = '.' endif + attrValue_ = trim(attrValue)//C_NULL_CHAR + ptr(1) = c_loc(attrValue_) + call h5screate_f(H5S_SCALAR_F,space_id,hdferr) - if (hdferr < 0) call IO_error(1,ext_msg='HDF5_addAttribute_str: h5screate_f') - call h5tcopy_f(H5T_NATIVE_CHARACTER, type_id, hdferr) - if (hdferr < 0) call IO_error(1,ext_msg='HDF5_addAttribute_str: h5tcopy_f') - call h5tset_size_f(type_id, int(len_trim(attrValue),HSIZE_T), hdferr) - if (hdferr < 0) call IO_error(1,ext_msg='HDF5_addAttribute_str: h5tset_size_f') + if(hdferr < 0) error stop 'HDF5 error' + call h5tcopy_f(H5T_STRING, type_id, hdferr) + if(hdferr < 0) error stop 'HDF5 error' call h5aexists_by_name_f(loc_id,trim(p),attrLabel,attrExists,hdferr) - if (hdferr < 0) call IO_error(1,ext_msg='HDF5_addAttribute_str: h5aexists_by_name_f') + if(hdferr < 0) error stop 'HDF5 error' if (attrExists) then - call h5adelete_by_name_f(loc_id, trim(p), attrLabel, hdferr) - if (hdferr < 0) call IO_error(1,ext_msg='HDF5_addAttribute_str: h5adelete_by_name_f') + call h5adelete_by_name_f(loc_id, trim(p), attrLabel, hdferr) + if(hdferr < 0) error stop 'HDF5 error' endif call h5acreate_by_name_f(loc_id,trim(p),trim(attrLabel),type_id,space_id,attr_id,hdferr) - if (hdferr < 0) call IO_error(1,ext_msg='HDF5_addAttribute_str: h5acreate_f') - call h5awrite_f(attr_id, type_id, trim(attrValue), int([1],HSIZE_T), hdferr) - if (hdferr < 0) call IO_error(1,ext_msg='HDF5_addAttribute_str: h5awrite_f') + if(hdferr < 0) error stop 'HDF5 error' + call h5awrite_f(attr_id, type_id, c_loc(ptr(1)), hdferr) + if(hdferr < 0) error stop 'HDF5 error' call h5aclose_f(attr_id,hdferr) - if (hdferr < 0) call IO_error(1,ext_msg='HDF5_addAttribute_str: h5aclose_f') + if(hdferr < 0) error stop 'HDF5 error' call h5tclose_f(type_id,hdferr) - if (hdferr < 0) call IO_error(1,ext_msg='HDF5_addAttribute_str: h5tclose_f') + if(hdferr < 0) error stop 'HDF5 error' call h5sclose_f(space_id,hdferr) - if (hdferr < 0) call IO_error(1,ext_msg='HDF5_addAttribute_str: h5sclose_f') + if(hdferr < 0) error stop 'HDF5 error' end subroutine HDF5_addAttribute_str @@ -351,21 +353,21 @@ subroutine HDF5_addAttribute_int(loc_id,attrLabel,attrValue,path) endif call h5screate_f(H5S_SCALAR_F,space_id,hdferr) - if (hdferr < 0) call IO_error(1,ext_msg='HDF5_addAttribute_int: h5screate_f') + if(hdferr < 0) error stop 'HDF5 error' call h5aexists_by_name_f(loc_id,trim(p),attrLabel,attrExists,hdferr) - if (hdferr < 0) call IO_error(1,ext_msg='HDF5_addAttribute_int: h5aexists_by_name_f') + if(hdferr < 0) error stop 'HDF5 error' if (attrExists) then call h5adelete_by_name_f(loc_id, trim(p), attrLabel, hdferr) - if (hdferr < 0) call IO_error(1,ext_msg='HDF5_addAttribute_int: h5adelete_by_name_f') + if(hdferr < 0) error stop 'HDF5 error' endif call h5acreate_by_name_f(loc_id,trim(p),trim(attrLabel),H5T_NATIVE_INTEGER,space_id,attr_id,hdferr) - if (hdferr < 0) call IO_error(1,ext_msg='HDF5_addAttribute_int: h5acreate_f') + if(hdferr < 0) error stop 'HDF5 error' call h5awrite_f(attr_id, H5T_NATIVE_INTEGER, attrValue, int([1],HSIZE_T), hdferr) - if (hdferr < 0) call IO_error(1,ext_msg='HDF5_addAttribute_int: h5awrite_f') + if(hdferr < 0) error stop 'HDF5 error' call h5aclose_f(attr_id,hdferr) - if (hdferr < 0) call IO_error(1,ext_msg='HDF5_addAttribute_int: h5tclose_f') + if(hdferr < 0) error stop 'HDF5 error' call h5sclose_f(space_id,hdferr) - if (hdferr < 0) call IO_error(1,ext_msg='HDF5_addAttribute_int: h5sclose_f') + if(hdferr < 0) error stop 'HDF5 error' end subroutine HDF5_addAttribute_int @@ -392,21 +394,21 @@ subroutine HDF5_addAttribute_real(loc_id,attrLabel,attrValue,path) endif call h5screate_f(H5S_SCALAR_F,space_id,hdferr) - if (hdferr < 0) call IO_error(1,ext_msg='HDF5_addAttribute_real: h5screate_f') + if(hdferr < 0) error stop 'HDF5 error' call h5aexists_by_name_f(loc_id,trim(p),attrLabel,attrExists,hdferr) - if (hdferr < 0) call IO_error(1,ext_msg='HDF5_addAttribute_real: h5aexists_by_name_f') + if(hdferr < 0) error stop 'HDF5 error' if (attrExists) then call h5adelete_by_name_f(loc_id, trim(p), attrLabel, hdferr) - if (hdferr < 0) call IO_error(1,ext_msg='HDF5_addAttribute_real: h5adelete_by_name_f') + if(hdferr < 0) error stop 'HDF5 error' endif call h5acreate_by_name_f(loc_id,trim(p),trim(attrLabel),H5T_NATIVE_DOUBLE,space_id,attr_id,hdferr) - if (hdferr < 0) call IO_error(1,ext_msg='HDF5_addAttribute_real: h5acreate_f') + if(hdferr < 0) error stop 'HDF5 error' call h5awrite_f(attr_id, H5T_NATIVE_DOUBLE, attrValue, int([1],HSIZE_T), hdferr) - if (hdferr < 0) call IO_error(1,ext_msg='HDF5_addAttribute_real: h5awrite_f') + if(hdferr < 0) error stop 'HDF5 error' call h5aclose_f(attr_id,hdferr) - if (hdferr < 0) call IO_error(1,ext_msg='HDF5_addAttribute_real: h5tclose_f') + if(hdferr < 0) error stop 'HDF5 error' call h5sclose_f(space_id,hdferr) - if (hdferr < 0) call IO_error(1,ext_msg='HDF5_addAttribute_real: h5sclose_f') + if(hdferr < 0) error stop 'HDF5 error' end subroutine HDF5_addAttribute_real @@ -436,21 +438,21 @@ subroutine HDF5_addAttribute_int_array(loc_id,attrLabel,attrValue,path) array_size = size(attrValue,kind=HSIZE_T) call h5screate_simple_f(1, array_size, space_id, hdferr, array_size) - if (hdferr < 0) call IO_error(1,ext_msg='HDF5_addAttribute_int_array: h5screate_f') + if(hdferr < 0) error stop 'HDF5 error' call h5aexists_by_name_f(loc_id,trim(p),attrLabel,attrExists,hdferr) - if (hdferr < 0) call IO_error(1,ext_msg='HDF5_addAttribute_int_array: h5aexists_by_name_f') + if(hdferr < 0) error stop 'HDF5 error' if (attrExists) then call h5adelete_by_name_f(loc_id, trim(p), attrLabel, hdferr) - if (hdferr < 0) call IO_error(1,ext_msg='HDF5_addAttribute_int_array: h5adelete_by_name_f') + if(hdferr < 0) error stop 'HDF5 error' endif call h5acreate_by_name_f(loc_id,trim(p),trim(attrLabel),H5T_NATIVE_INTEGER,space_id,attr_id,hdferr) - if (hdferr < 0) call IO_error(1,ext_msg='HDF5_addAttribute_int_array: h5acreate_f') + if(hdferr < 0) error stop 'HDF5 error' call h5awrite_f(attr_id, H5T_NATIVE_INTEGER, attrValue, array_size, hdferr) - if (hdferr < 0) call IO_error(1,ext_msg='HDF5_addAttribute_int_array: h5awrite_f') + if(hdferr < 0) error stop 'HDF5 error' call h5aclose_f(attr_id,hdferr) - if (hdferr < 0) call IO_error(1,ext_msg='HDF5_addAttribute_int_array: h5tclose_f') + if(hdferr < 0) error stop 'HDF5 error' call h5sclose_f(space_id,hdferr) - if (hdferr < 0) call IO_error(1,ext_msg='HDF5_addAttribute_int_array: h5sclose_f') + if(hdferr < 0) error stop 'HDF5 error' end subroutine HDF5_addAttribute_int_array @@ -480,21 +482,21 @@ subroutine HDF5_addAttribute_real_array(loc_id,attrLabel,attrValue,path) array_size = size(attrValue,kind=HSIZE_T) call h5screate_simple_f(1, array_size, space_id, hdferr, array_size) - if (hdferr < 0) call IO_error(1,ext_msg='HDF5_addAttribute_int_array: h5screate_f') + if(hdferr < 0) error stop 'HDF5 error' call h5aexists_by_name_f(loc_id,trim(p),attrLabel,attrExists,hdferr) - if (hdferr < 0) call IO_error(1,ext_msg='HDF5_addAttribute_int_array: h5aexists_by_name_f') + if(hdferr < 0) error stop 'HDF5 error' if (attrExists) then call h5adelete_by_name_f(loc_id, trim(p), attrLabel, hdferr) - if (hdferr < 0) call IO_error(1,ext_msg='HDF5_addAttribute_int_array: h5adelete_by_name_f') + if(hdferr < 0) error stop 'HDF5 error' endif call h5acreate_by_name_f(loc_id,trim(p),trim(attrLabel),H5T_NATIVE_DOUBLE,space_id,attr_id,hdferr) - if (hdferr < 0) call IO_error(1,ext_msg='HDF5_addAttribute_int_array: h5acreate_f') + if(hdferr < 0) error stop 'HDF5 error' call h5awrite_f(attr_id, H5T_NATIVE_DOUBLE, attrValue, array_size, hdferr) - if (hdferr < 0) call IO_error(1,ext_msg='HDF5_addAttribute_int_array: h5awrite_f') + if(hdferr < 0) error stop 'HDF5 error' call h5aclose_f(attr_id,hdferr) - if (hdferr < 0) call IO_error(1,ext_msg='HDF5_addAttribute_int_array: h5tclose_f') + if(hdferr < 0) error stop 'HDF5 error' call h5sclose_f(space_id,hdferr) - if (hdferr < 0) call IO_error(1,ext_msg='HDF5_addAttribute_int_array: h5sclose_f') + if(hdferr < 0) error stop 'HDF5 error' end subroutine HDF5_addAttribute_real_array @@ -510,13 +512,13 @@ subroutine HDF5_setLink(loc_id,target_name,link_name) logical :: linkExists call h5lexists_f(loc_id, link_name,linkExists, hdferr) - if (hdferr < 0) call IO_error(1,ext_msg = 'HDF5_setLink: h5lexists_soft_f ('//trim(link_name)//')') + if(hdferr < 0) error stop 'HDF5 error' if (linkExists) then call h5ldelete_f(loc_id,link_name, hdferr) - if (hdferr < 0) call IO_error(1,ext_msg = 'HDF5_setLink: h5ldelete_soft_f ('//trim(link_name)//')') + if(hdferr < 0) error stop 'HDF5 error' endif call h5lcreate_soft_f(target_name, loc_id, link_name, hdferr) - if (hdferr < 0) call IO_error(1,ext_msg = 'HDF5_setLink: h5lcreate_soft_f ('//trim(target_name)//' '//trim(link_name)//')') + if(hdferr < 0) error stop 'HDF5 error' end subroutine HDF5_setLink @@ -555,7 +557,7 @@ subroutine HDF5_read_real1(loc_id,dataset,datasetName,parallel) call h5dread_f(dset_id, H5T_NATIVE_DOUBLE,dataset,totalShape, hdferr,& file_space_id = filespace_id, xfer_prp = plist_id, mem_space_id = memspace_id) - if (hdferr < 0) call IO_error(1,ext_msg='HDF5_read_real1: h5dread_f') + if(hdferr < 0) error stop 'HDF5 error' call finalize_read(dset_id, filespace_id, memspace_id, plist_id, aplist_id) @@ -595,7 +597,7 @@ subroutine HDF5_read_real2(loc_id,dataset,datasetName,parallel) call h5dread_f(dset_id, H5T_NATIVE_DOUBLE,dataset,totalShape, hdferr,& file_space_id = filespace_id, xfer_prp = plist_id, mem_space_id = memspace_id) - if (hdferr < 0) call IO_error(1,ext_msg='HDF5_read_real2: h5dread_f') + if(hdferr < 0) error stop 'HDF5 error' call finalize_read(dset_id, filespace_id, memspace_id, plist_id, aplist_id) @@ -635,7 +637,7 @@ subroutine HDF5_read_real3(loc_id,dataset,datasetName,parallel) call h5dread_f(dset_id, H5T_NATIVE_DOUBLE,dataset,totalShape, hdferr,& file_space_id = filespace_id, xfer_prp = plist_id, mem_space_id = memspace_id) - if (hdferr < 0) call IO_error(1,ext_msg='HDF5_read_real3: h5dread_f') + if(hdferr < 0) error stop 'HDF5 error' call finalize_read(dset_id, filespace_id, memspace_id, plist_id, aplist_id) @@ -675,7 +677,7 @@ subroutine HDF5_read_real4(loc_id,dataset,datasetName,parallel) call h5dread_f(dset_id, H5T_NATIVE_DOUBLE,dataset,totalShape, hdferr,& file_space_id = filespace_id, xfer_prp = plist_id, mem_space_id = memspace_id) - if (hdferr < 0) call IO_error(1,ext_msg='HDF5_read_real4: h5dread_f') + if(hdferr < 0) error stop 'HDF5 error' call finalize_read(dset_id, filespace_id, memspace_id, plist_id, aplist_id) @@ -715,7 +717,7 @@ subroutine HDF5_read_real5(loc_id,dataset,datasetName,parallel) call h5dread_f(dset_id, H5T_NATIVE_DOUBLE,dataset,totalShape, hdferr,& file_space_id = filespace_id, xfer_prp = plist_id, mem_space_id = memspace_id) - if (hdferr < 0) call IO_error(1,ext_msg='HDF5_read_real5: h5dread_f') + if(hdferr < 0) error stop 'HDF5 error' call finalize_read(dset_id, filespace_id, memspace_id, plist_id, aplist_id) @@ -755,7 +757,7 @@ subroutine HDF5_read_real6(loc_id,dataset,datasetName,parallel) call h5dread_f(dset_id, H5T_NATIVE_DOUBLE,dataset,totalShape, hdferr,& file_space_id = filespace_id, xfer_prp = plist_id, mem_space_id = memspace_id) - if (hdferr < 0) call IO_error(1,ext_msg='HDF5_read_real6: h5dread_f') + if(hdferr < 0) error stop 'HDF5 error' call finalize_read(dset_id, filespace_id, memspace_id, plist_id, aplist_id) @@ -795,7 +797,7 @@ subroutine HDF5_read_real7(loc_id,dataset,datasetName,parallel) call h5dread_f(dset_id, H5T_NATIVE_DOUBLE,dataset,totalShape, hdferr,& file_space_id = filespace_id, xfer_prp = plist_id, mem_space_id = memspace_id) - if (hdferr < 0) call IO_error(1,ext_msg='HDF5_read_real7: h5dread_f') + if(hdferr < 0) error stop 'HDF5 error' call finalize_read(dset_id, filespace_id, memspace_id, plist_id, aplist_id) @@ -837,7 +839,7 @@ subroutine HDF5_read_int1(loc_id,dataset,datasetName,parallel) call h5dread_f(dset_id, H5T_NATIVE_INTEGER,dataset,totalShape, hdferr,& file_space_id = filespace_id, xfer_prp = plist_id, mem_space_id = memspace_id) - if (hdferr < 0) call IO_error(1,ext_msg='HDF5_read_int1: h5dread_f') + if(hdferr < 0) error stop 'HDF5 error' call finalize_read(dset_id, filespace_id, memspace_id, plist_id, aplist_id) @@ -877,7 +879,7 @@ subroutine HDF5_read_int2(loc_id,dataset,datasetName,parallel) call h5dread_f(dset_id, H5T_NATIVE_INTEGER,dataset,totalShape, hdferr,& file_space_id = filespace_id, xfer_prp = plist_id, mem_space_id = memspace_id) - if (hdferr < 0) call IO_error(1,ext_msg='HDF5_read_int2: h5dread_f') + if(hdferr < 0) error stop 'HDF5 error' call finalize_read(dset_id, filespace_id, memspace_id, plist_id, aplist_id) @@ -917,7 +919,7 @@ subroutine HDF5_read_int3(loc_id,dataset,datasetName,parallel) call h5dread_f(dset_id, H5T_NATIVE_INTEGER,dataset,totalShape, hdferr,& file_space_id = filespace_id, xfer_prp = plist_id, mem_space_id = memspace_id) - if (hdferr < 0) call IO_error(1,ext_msg='HDF5_read_int3: h5dread_f') + if(hdferr < 0) error stop 'HDF5 error' call finalize_read(dset_id, filespace_id, memspace_id, plist_id, aplist_id) @@ -957,7 +959,7 @@ subroutine HDF5_read_int4(loc_id,dataset,datasetName,parallel) call h5dread_f(dset_id, H5T_NATIVE_INTEGER,dataset,totalShape, hdferr,& file_space_id = filespace_id, xfer_prp = plist_id, mem_space_id = memspace_id) - if (hdferr < 0) call IO_error(1,ext_msg='HDF5_read_int4: h5dread_f') + if(hdferr < 0) error stop 'HDF5 error' call finalize_read(dset_id, filespace_id, memspace_id, plist_id, aplist_id) @@ -997,7 +999,7 @@ subroutine HDF5_read_int5(loc_id,dataset,datasetName,parallel) call h5dread_f(dset_id, H5T_NATIVE_INTEGER,dataset,totalShape, hdferr,& file_space_id = filespace_id, xfer_prp = plist_id, mem_space_id = memspace_id) - if (hdferr < 0) call IO_error(1,ext_msg='HDF5_read_int5: h5dread_f') + if(hdferr < 0) error stop 'HDF5 error' call finalize_read(dset_id, filespace_id, memspace_id, plist_id, aplist_id) @@ -1037,7 +1039,7 @@ subroutine HDF5_read_int6(loc_id,dataset,datasetName,parallel) call h5dread_f(dset_id, H5T_NATIVE_INTEGER,dataset,totalShape, hdferr,& file_space_id = filespace_id, xfer_prp = plist_id, mem_space_id = memspace_id) - if (hdferr < 0) call IO_error(1,ext_msg='HDF5_read_int6: h5dread_f') + if(hdferr < 0) error stop 'HDF5 error' call finalize_read(dset_id, filespace_id, memspace_id, plist_id, aplist_id) @@ -1077,7 +1079,7 @@ subroutine HDF5_read_int7(loc_id,dataset,datasetName,parallel) call h5dread_f(dset_id, H5T_NATIVE_INTEGER,dataset,totalShape, hdferr,& file_space_id = filespace_id, xfer_prp = plist_id, mem_space_id = memspace_id) - if (hdferr < 0) call IO_error(1,ext_msg='HDF5_read_int7: h5dread_f') + if(hdferr < 0) error stop 'HDF5 error' call finalize_read(dset_id, filespace_id, memspace_id, plist_id, aplist_id) @@ -1118,7 +1120,7 @@ subroutine HDF5_write_real1(loc_id,dataset,datasetName,parallel) if (product(totalShape) /= 0) then call h5dwrite_f(dset_id, H5T_NATIVE_DOUBLE,dataset,int(totalShape,HSIZE_T), hdferr,& file_space_id = filespace_id, mem_space_id = memspace_id, xfer_prp = plist_id) - if (hdferr < 0) call IO_error(1,ext_msg='HDF5_write_real1: h5dwrite_f') + if(hdferr < 0) error stop 'HDF5 error' endif call finalize_write(plist_id, dset_id, filespace_id, memspace_id) @@ -1159,7 +1161,7 @@ subroutine HDF5_write_real2(loc_id,dataset,datasetName,parallel) if (product(totalShape) /= 0) then call h5dwrite_f(dset_id, H5T_NATIVE_DOUBLE,dataset,int(totalShape,HSIZE_T), hdferr,& file_space_id = filespace_id, mem_space_id = memspace_id, xfer_prp = plist_id) - if (hdferr < 0) call IO_error(1,ext_msg='HDF5_write_real2: h5dwrite_f') + if(hdferr < 0) error stop 'HDF5 error' endif call finalize_write(plist_id, dset_id, filespace_id, memspace_id) @@ -1200,7 +1202,7 @@ subroutine HDF5_write_real3(loc_id,dataset,datasetName,parallel) if (product(totalShape) /= 0) then call h5dwrite_f(dset_id, H5T_NATIVE_DOUBLE,dataset,int(totalShape,HSIZE_T), hdferr,& file_space_id = filespace_id, mem_space_id = memspace_id, xfer_prp = plist_id) - if (hdferr < 0) call IO_error(1,ext_msg='HDF5_write_real3: h5dwrite_f') + if(hdferr < 0) error stop 'HDF5 error' endif call finalize_write(plist_id, dset_id, filespace_id, memspace_id) @@ -1241,7 +1243,7 @@ subroutine HDF5_write_real4(loc_id,dataset,datasetName,parallel) if (product(totalShape) /= 0) then call h5dwrite_f(dset_id, H5T_NATIVE_DOUBLE,dataset,int(totalShape,HSIZE_T), hdferr,& file_space_id = filespace_id, mem_space_id = memspace_id, xfer_prp = plist_id) - if (hdferr < 0) call IO_error(1,ext_msg='HDF5_write_real4: h5dwrite_f') + if(hdferr < 0) error stop 'HDF5 error' endif call finalize_write(plist_id, dset_id, filespace_id, memspace_id) @@ -1283,7 +1285,7 @@ subroutine HDF5_write_real5(loc_id,dataset,datasetName,parallel) if (product(totalShape) /= 0) then call h5dwrite_f(dset_id, H5T_NATIVE_DOUBLE,dataset,int(totalShape,HSIZE_T), hdferr,& file_space_id = filespace_id, mem_space_id = memspace_id, xfer_prp = plist_id) - if (hdferr < 0) call IO_error(1,ext_msg='HDF5_write_real5: h5dwrite_f') + if(hdferr < 0) error stop 'HDF5 error' endif call finalize_write(plist_id, dset_id, filespace_id, memspace_id) @@ -1324,7 +1326,7 @@ subroutine HDF5_write_real6(loc_id,dataset,datasetName,parallel) if (product(totalShape) /= 0) then call h5dwrite_f(dset_id, H5T_NATIVE_DOUBLE,dataset,int(totalShape,HSIZE_T), hdferr,& file_space_id = filespace_id, mem_space_id = memspace_id, xfer_prp = plist_id) - if (hdferr < 0) call IO_error(1,ext_msg='HDF5_write_real6: h5dwrite_f') + if(hdferr < 0) error stop 'HDF5 error' endif call finalize_write(plist_id, dset_id, filespace_id, memspace_id) @@ -1365,7 +1367,7 @@ subroutine HDF5_write_real7(loc_id,dataset,datasetName,parallel) if (product(totalShape) /= 0) then call h5dwrite_f(dset_id, H5T_NATIVE_DOUBLE,dataset,int(totalShape,HSIZE_T), hdferr,& file_space_id = filespace_id, mem_space_id = memspace_id, xfer_prp = plist_id) - if (hdferr < 0) call IO_error(1,ext_msg='HDF5_write_real7: h5dwrite_f') + if(hdferr < 0) error stop 'HDF5 error' endif call finalize_write(plist_id, dset_id, filespace_id, memspace_id) @@ -1407,7 +1409,7 @@ subroutine HDF5_write_int1(loc_id,dataset,datasetName,parallel) if (product(totalShape) /= 0) then call h5dwrite_f(dset_id, H5T_NATIVE_INTEGER,dataset,int(totalShape,HSIZE_T), hdferr,& file_space_id = filespace_id, mem_space_id = memspace_id, xfer_prp = plist_id) - if (hdferr < 0) call IO_error(1,ext_msg='HDF5_write_int1: h5dwrite_f') + if(hdferr < 0) error stop 'HDF5 error' endif call finalize_write(plist_id, dset_id, filespace_id, memspace_id) @@ -1448,7 +1450,7 @@ subroutine HDF5_write_int2(loc_id,dataset,datasetName,parallel) if (product(totalShape) /= 0) then call h5dwrite_f(dset_id, H5T_NATIVE_INTEGER,dataset,int(totalShape,HSIZE_T), hdferr,& file_space_id = filespace_id, mem_space_id = memspace_id, xfer_prp = plist_id) - if (hdferr < 0) call IO_error(1,ext_msg='HDF5_write_int2: h5dwrite_f') + if(hdferr < 0) error stop 'HDF5 error' endif call finalize_write(plist_id, dset_id, filespace_id, memspace_id) @@ -1489,7 +1491,7 @@ subroutine HDF5_write_int3(loc_id,dataset,datasetName,parallel) if (product(totalShape) /= 0) then call h5dwrite_f(dset_id, H5T_NATIVE_INTEGER,dataset,int(totalShape,HSIZE_T), hdferr,& file_space_id = filespace_id, mem_space_id = memspace_id, xfer_prp = plist_id) - if (hdferr < 0) call IO_error(1,ext_msg='HDF5_write_int3: h5dwrite_f') + if(hdferr < 0) error stop 'HDF5 error' endif call finalize_write(plist_id, dset_id, filespace_id, memspace_id) @@ -1530,7 +1532,7 @@ subroutine HDF5_write_int4(loc_id,dataset,datasetName,parallel) if (product(totalShape) /= 0) then call h5dwrite_f(dset_id, H5T_NATIVE_INTEGER,dataset,int(totalShape,HSIZE_T), hdferr,& file_space_id = filespace_id, mem_space_id = memspace_id, xfer_prp = plist_id) - if (hdferr < 0) call IO_error(1,ext_msg='HDF5_write_int4: h5dwrite_f') + if(hdferr < 0) error stop 'HDF5 error' endif call finalize_write(plist_id, dset_id, filespace_id, memspace_id) @@ -1571,7 +1573,7 @@ subroutine HDF5_write_int5(loc_id,dataset,datasetName,parallel) if (product(totalShape) /= 0) then call h5dwrite_f(dset_id, H5T_NATIVE_INTEGER,dataset,int(totalShape,HSIZE_T), hdferr,& file_space_id = filespace_id, mem_space_id = memspace_id, xfer_prp = plist_id) - if (hdferr < 0) call IO_error(1,ext_msg='HDF5_write_int5: h5dwrite_f') + if(hdferr < 0) error stop 'HDF5 error' endif call finalize_write(plist_id, dset_id, filespace_id, memspace_id) @@ -1612,7 +1614,7 @@ subroutine HDF5_write_int6(loc_id,dataset,datasetName,parallel) if (product(totalShape) /= 0) then call h5dwrite_f(dset_id, H5T_NATIVE_INTEGER,dataset,int(totalShape,HSIZE_T), hdferr,& file_space_id = filespace_id, mem_space_id = memspace_id, xfer_prp = plist_id) - if (hdferr < 0) call IO_error(1,ext_msg='HDF5_write_int6: h5dwrite_f') + if(hdferr < 0) error stop 'HDF5 error' endif call finalize_write(plist_id, dset_id, filespace_id, memspace_id) @@ -1653,7 +1655,7 @@ subroutine HDF5_write_int7(loc_id,dataset,datasetName,parallel) if (product(totalShape) /= 0) then call h5dwrite_f(dset_id, H5T_NATIVE_INTEGER,dataset,int(totalShape,HSIZE_T), hdferr,& file_space_id = filespace_id, mem_space_id = memspace_id, xfer_prp = plist_id) - if (hdferr < 0) call IO_error(1,ext_msg='HDF5_write_int7: h5dwrite_f') + if(hdferr < 0) error stop 'HDF5 error' endif call finalize_write(plist_id, dset_id, filespace_id, memspace_id) @@ -1729,7 +1731,7 @@ subroutine HDF5_write_rotation(loc_id,dataset,datasetName,parallel) file_space_id = filespace_id, mem_space_id = memspace_id, xfer_prp = plist_id) call h5dwrite_f(dset_id, z_id,dataset_asArray(4,:),int(totalShape,HSIZE_T), hdferr,& file_space_id = filespace_id, mem_space_id = memspace_id, xfer_prp = plist_id) - if (hdferr < 0) call IO_error(1,ext_msg='HDF5_write_rotation: h5dwrite_f') + if(hdferr < 0) error stop 'HDF5 error' endif call finalize_write(plist_id, dset_id, filespace_id, memspace_id) @@ -1762,7 +1764,7 @@ subroutine initialize_read(dset_id, filespace_id, memspace_id, plist_id, aplist_ !------------------------------------------------------------------------------------------------- ! creating a property list for transfer properties (is collective for MPI) call h5pcreate_f(H5P_DATASET_XFER_F, plist_id, hdferr) - if (hdferr < 0) call IO_error(1,ext_msg='initialize_read: h5pcreate_f') + if(hdferr < 0) error stop 'HDF5 error' !-------------------------------------------------------------------------------------------------- readSize = 0 @@ -1770,9 +1772,9 @@ subroutine initialize_read(dset_id, filespace_id, memspace_id, plist_id, aplist_ #ifdef PETSc if (parallel) then call h5pset_dxpl_mpio_f(plist_id, H5FD_MPIO_COLLECTIVE_F, hdferr) - if (hdferr < 0) call IO_error(1,ext_msg='initialize_read: h5pset_dxpl_mpio_f') + if(hdferr < 0) error stop 'HDF5 error' call MPI_allreduce(MPI_IN_PLACE,readSize,worldsize,MPI_INT,MPI_SUM,PETSC_COMM_WORLD,ierr) ! get total output size over each process - if (ierr /= 0) call IO_error(894,ext_msg='initialize_read: MPI_allreduce') + if (ierr /= 0) error stop 'MPI error' endif #endif myStart = int(0,HSIZE_T) @@ -1782,28 +1784,28 @@ subroutine initialize_read(dset_id, filespace_id, memspace_id, plist_id, aplist_ !-------------------------------------------------------------------------------------------------- ! create dataspace in memory (local shape) call h5screate_simple_f(size(localShape), localShape, memspace_id, hdferr, localShape) - if (hdferr < 0) call IO_error(1,ext_msg='initialize_read: h5screate_simple_f/memspace_id') + if(hdferr < 0) error stop 'HDF5 error' !-------------------------------------------------------------------------------------------------- ! creating a property list for IO and set it to collective call h5pcreate_f(H5P_DATASET_ACCESS_F, aplist_id, hdferr) - if (hdferr < 0) call IO_error(1,ext_msg='initialize_read: h5pcreate_f') + if(hdferr < 0) error stop 'HDF5 error' #ifdef PETSc call h5pset_all_coll_metadata_ops_f(aplist_id, .true., hdferr) - if (hdferr < 0) call IO_error(1,ext_msg='initialize_read: h5pset_all_coll_metadata_ops_f') + if(hdferr < 0) error stop 'HDF5 error' #endif !-------------------------------------------------------------------------------------------------- ! open the dataset in the file and get the space ID call h5dopen_f(loc_id,datasetName,dset_id,hdferr, dapl_id = aplist_id) - if (hdferr < 0) call IO_error(1,ext_msg='initialize_read: h5dopen_f') + if(hdferr < 0) error stop 'HDF5 error' call h5dget_space_f(dset_id, filespace_id, hdferr) - if (hdferr < 0) call IO_error(1,ext_msg='initialize_read: h5dget_space_f') + if(hdferr < 0) error stop 'HDF5 error' !-------------------------------------------------------------------------------------------------- ! select a hyperslab (the portion of the current process) in the file call h5sselect_hyperslab_f(filespace_id, H5S_SELECT_SET_F, myStart, localShape, hdferr) - if (hdferr < 0) call IO_error(1,ext_msg='initialize_read: h5sselect_hyperslab_f') + if(hdferr < 0) error stop 'HDF5 error' end subroutine initialize_read @@ -1817,15 +1819,15 @@ subroutine finalize_read(dset_id, filespace_id, memspace_id, plist_id, aplist_id integer :: hdferr call h5pclose_f(plist_id, hdferr) - if (hdferr < 0) call IO_error(1,ext_msg='finalize_read: plist_id') + if(hdferr < 0) error stop 'HDF5 error' call h5pclose_f(aplist_id, hdferr) - if (hdferr < 0) call IO_error(1,ext_msg='finalize_read: aplist_id') + if(hdferr < 0) error stop 'HDF5 error' call h5dclose_f(dset_id, hdferr) - if (hdferr < 0) call IO_error(1,ext_msg='finalize_read: h5dclose_f') + if(hdferr < 0) error stop 'HDF5 error' call h5sclose_f(filespace_id, hdferr) - if (hdferr < 0) call IO_error(1,ext_msg='finalize_read: h5sclose_f/filespace_id') + if(hdferr < 0) error stop 'HDF5 error' call h5sclose_f(memspace_id, hdferr) - if (hdferr < 0) call IO_error(1,ext_msg='finalize_read: h5sclose_f/memspace_id') + if(hdferr < 0) error stop 'HDF5 error' end subroutine finalize_read @@ -1856,11 +1858,11 @@ subroutine initialize_write(dset_id, filespace_id, memspace_id, plist_id, & !------------------------------------------------------------------------------------------------- ! creating a property list for transfer properties (is collective when reading in parallel) call h5pcreate_f(H5P_DATASET_XFER_F, plist_id, hdferr) - if (hdferr < 0) call IO_error(1,ext_msg='initialize_write: h5pcreate_f') + if(hdferr < 0) error stop 'HDF5 error' #ifdef PETSc if (parallel) then call h5pset_dxpl_mpio_f(plist_id, H5FD_MPIO_COLLECTIVE_F, hdferr) - if (hdferr < 0) call IO_error(1,ext_msg='initialize_write: h5pset_dxpl_mpio_f') + if(hdferr < 0) error stop 'HDF5 error' endif #endif @@ -1871,7 +1873,7 @@ subroutine initialize_write(dset_id, filespace_id, memspace_id, plist_id, & #ifdef PETSc if (parallel) then call MPI_allreduce(MPI_IN_PLACE,writeSize,worldsize,MPI_INT,MPI_SUM,PETSC_COMM_WORLD,ierr) ! get total output size over each process - if (ierr /= 0) call IO_error(894,ext_msg='initialize_write: MPI_allreduce') + if (ierr /= 0) error stop 'MPI error' endif #endif myStart = int(0,HSIZE_T) @@ -1881,16 +1883,16 @@ subroutine initialize_write(dset_id, filespace_id, memspace_id, plist_id, & !-------------------------------------------------------------------------------------------------- ! create dataspace in memory (local shape) and in file (global shape) call h5screate_simple_f(size(myShape), myShape, memspace_id, hdferr, myShape) - if (hdferr < 0) call IO_error(1,ext_msg='initialize_write: h5dopen_f') + if(hdferr < 0) error stop 'HDF5 error' call h5screate_simple_f(size(totalShape), totalShape, filespace_id, hdferr, totalShape) - if (hdferr < 0) call IO_error(1,ext_msg='initialize_write: h5dget_space_f') + if(hdferr < 0) error stop 'HDF5 error' !-------------------------------------------------------------------------------------------------- ! create dataset in the file and select a hyperslab from it (the portion of the current process) call h5dcreate_f(loc_id, trim(datasetName), datatype, filespace_id, dset_id, hdferr) - if (hdferr < 0) call IO_error(1,ext_msg='initialize_write: h5dcreate_f') + if(hdferr < 0) error stop 'HDF5 error' call h5sselect_hyperslab_f(filespace_id, H5S_SELECT_SET_F, myStart, myShape, hdferr) - if (hdferr < 0) call IO_error(1,ext_msg='initialize_write: h5sselect_hyperslab_f') + if(hdferr < 0) error stop 'HDF5 error' end subroutine initialize_write @@ -1904,13 +1906,13 @@ subroutine finalize_write(plist_id, dset_id, filespace_id, memspace_id) integer :: hdferr call h5pclose_f(plist_id, hdferr) - if (hdferr < 0) call IO_error(1,ext_msg='finalize_write: plist_id') + if(hdferr < 0) error stop 'HDF5 error' call h5dclose_f(dset_id, hdferr) - if (hdferr < 0) call IO_error(1,ext_msg='finalize_write: h5dclose_f') + if(hdferr < 0) error stop 'HDF5 error' call h5sclose_f(filespace_id, hdferr) - if (hdferr < 0) call IO_error(1,ext_msg='finalize_write: h5sclose_f/filespace_id') + if(hdferr < 0) error stop 'HDF5 error' call h5sclose_f(memspace_id, hdferr) - if (hdferr < 0) call IO_error(1,ext_msg='finalize_write: h5sclose_f/memspace_id') + if(hdferr < 0) error stop 'HDF5 error' end subroutine finalize_write diff --git a/src/IO.f90 b/src/IO.f90 index 260bd94b8..36063e963 100644 --- a/src/IO.f90 +++ b/src/IO.f90 @@ -367,12 +367,8 @@ subroutine IO_error(error_ID,el,ip,g,instance,ext_msg) ! file handling errors case (100) msg = 'could not open file:' - case (101) - msg = 'write error for file:' case (102) msg = 'could not read file:' - case (106) - msg = 'working directory does not exist:' !-------------------------------------------------------------------------------------------------- ! file parsing errors @@ -395,14 +391,10 @@ subroutine IO_error(error_ID,el,ip,g,instance,ext_msg) msg = 'hex lattice structure with invalid c/a ratio' case (132) msg = 'trans_lattice_structure not possible' - case (133) - msg = 'transformed hex lattice structure with invalid c/a ratio' case (134) msg = 'negative lattice parameter' case (135) msg = 'zero entry on stiffness diagonal' - case (136) - msg = 'zero entry on stiffness diagonal for transformed phase' case (137) msg = 'not defined for lattice structure' case (138) @@ -431,8 +423,6 @@ subroutine IO_error(error_ID,el,ip,g,instance,ext_msg) ! material error messages and related messages in mesh case (150) msg = 'index out of bounds' - case (151) - msg = 'material has no constituents' case (153) msg = 'sum of phase fractions differs from 1' case (155) @@ -463,10 +453,6 @@ subroutine IO_error(error_ID,el,ip,g,instance,ext_msg) !-------------------------------------------------------------------------------------------------- ! math errors - case (400) - msg = 'matrix inversion error' - case (401) - msg = 'error in Eigenvalue calculation' case (402) msg = 'invalid orientation specified' @@ -499,10 +485,6 @@ subroutine IO_error(error_ID,el,ip,g,instance,ext_msg) !------------------------------------------------------------------------------------------------- ! errors related to the grid solver - case (809) - msg = 'initializing FFTW' - case (810) - msg = 'FFTW plan creation' case (831) msg = 'mask consistency violated in grid load case' case (832) @@ -587,45 +569,20 @@ subroutine IO_warning(warning_ID,el,ip,g,ext_msg) character(len=pStringLen) :: formatString select case (warning_ID) - case (1) - msg = 'unknown key' - case (34) - msg = 'invalid restart increment given' - case (35) - msg = 'could not get $DAMASK_NUM_THREADS' - case (40) - msg = 'found spectral solver parameter' case (42) msg = 'parameter has no effect' - case (43) - msg = 'main diagonal of C66 close to zero' case (47) msg = 'no valid parameter for FFTW, using FFTW_PATIENT' - case (50) - msg = 'not all available slip system families are defined' - case (51) - msg = 'not all available twin system families are defined' - case (52) - msg = 'not all available parameters are defined' - case (53) - msg = 'not all available transformation system families are defined' - case (101) - msg = 'crystallite debugging off' - case (201) - msg = 'position not found when parsing line' case (207) msg = 'line truncated' case (600) msg = 'crystallite responds elastically' case (601) msg = 'stiffness close to zero' - case (650) - msg = 'polar decomposition failed' case (700) msg = 'unknown crystal symmetry' case (709) msg = 'read only the first document' - case (850) msg = 'max number of cut back exceeded, terminating' case default diff --git a/src/commercialFEM_fileList.f90 b/src/commercialFEM_fileList.f90 index f4eb5d78c..d161b36eb 100644 --- a/src/commercialFEM_fileList.f90 +++ b/src/commercialFEM_fileList.f90 @@ -25,7 +25,7 @@ #include "material.f90" #include "lattice.f90" #include "constitutive.f90" -#include "constitutive_plastic.f90" +#include "constitutive_mech.f90" #include "constitutive_plastic_none.f90" #include "constitutive_plastic_isotropic.f90" #include "constitutive_plastic_phenopowerlaw.f90" diff --git a/src/constitutive.f90 b/src/constitutive.f90 index 358937e4b..470ac4dc7 100644 --- a/src/constitutive.f90 +++ b/src/constitutive.f90 @@ -19,7 +19,7 @@ module constitutive implicit none private - integer(kind(ELASTICITY_undefined_ID)), dimension(:), allocatable, protected :: & + integer(kind(ELASTICITY_undefined_ID)), dimension(:), allocatable :: & !ToDo: old intel compiler complains about protected phase_elasticity !< elasticity of each phase integer(kind(PLASTICITY_undefined_ID)), dimension(:), allocatable :: & !ToDo: old intel compiler complains about protected @@ -52,8 +52,8 @@ module constitutive interface - module subroutine plastic_init - end subroutine plastic_init + module subroutine mech_init + end subroutine mech_init module subroutine damage_init end subroutine damage_init @@ -343,6 +343,25 @@ module constitutive end interface constitutive_dependentState + interface constitutive_SandItsTangents + + module subroutine constitutive_hooke_SandItsTangents(S, dS_dFe, dS_dFi, Fe, Fi, ipc, ip, el) + integer, intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + real(pReal), intent(in), dimension(3,3) :: & + Fe, & !< elastic deformation gradient + Fi !< intermediate deformation gradient + real(pReal), intent(out), dimension(3,3) :: & + S !< 2nd Piola-Kirchhoff stress tensor + real(pReal), intent(out), dimension(3,3,3,3) :: & + dS_dFe, & !< derivative of 2nd P-K stress with respect to elastic deformation gradient + dS_dFi !< derivative of 2nd P-K stress with respect to intermediate deformation gradient + end subroutine constitutive_hooke_SandItsTangents + + end interface constitutive_SandItsTangents + type :: tDebugOptions logical :: & @@ -385,14 +404,10 @@ subroutine constitutive_init integer :: & p, & !< counter in phase loop - s, & !< counter in source loop - stiffDegradationCtr + s !< counter in source loop class (tNode), pointer :: & debug_constitutive, & - phases, & - phase, & - elastic, & - stiffDegradation + phases debug_constitutive => config_debug%get('constitutive', defaultVal=emptyList) debugConstitutive%basic = debug_constitutive%contains('basic') @@ -402,52 +417,15 @@ subroutine constitutive_init debugConstitutive%ip = config_debug%get_asInt('integrationpoint',defaultVal = 1) debugConstitutive%grain = config_debug%get_asInt('grain',defaultVal = 1) -!------------------------------------------------------------------------------------------------- -! initialize elasticity (hooke) !ToDO: Maybe move to elastic submodule along with function homogenizedC? - phases => config_material%get('phase') - allocate(phase_elasticity(phases%length), source = ELASTICITY_undefined_ID) - allocate(phase_elasticityInstance(phases%length), source = 0) - allocate(phase_NstiffnessDegradations(phases%length),source=0) - - do p = 1, phases%length - phase => phases%get(p) - elastic => phase%get('elasticity') - if(elastic%get_asString('type') == 'hooke') then - phase_elasticity(p) = ELASTICITY_HOOKE_ID - else - call IO_error(200,ext_msg=elastic%get_asString('type')) - endif - stiffDegradation => phase%get('stiffness_degradation',defaultVal=emptyList) ! check for stiffness degradation mechanisms - phase_NstiffnessDegradations(p) = stiffDegradation%length - enddo - - allocate(phase_stiffnessDegradation(maxval(phase_NstiffnessDegradations),phases%length), & - source=STIFFNESS_DEGRADATION_undefined_ID) - - if(maxVal(phase_NstiffnessDegradations)/=0) then - do p = 1, phases%length - phase => phases%get(p) - stiffDegradation => phase%get('stiffness_degradation',defaultVal=emptyList) - do stiffDegradationCtr = 1, stiffDegradation%length - if(stiffDegradation%get_asString(stiffDegradationCtr) == 'damage') & - phase_stiffnessDegradation(stiffDegradationCtr,p) = STIFFNESS_DEGRADATION_damage_ID - enddo - enddo - endif - - do p = 1, phases%length - phase_elasticityInstance(p) = count(phase_elasticity(1:p) == phase_elasticity(p)) - enddo - - !-------------------------------------------------------------------------------------------------- ! initialize constitutive laws - call plastic_init + call mech_init call damage_init call thermal_init print'(/,a)', ' <<<+- constitutive init -+>>>'; flush(IO_STDOUT) + phases => config_material%get('phase') constitutive_source_maxSizeDotState = 0 PhaseLoop2:do p = 1,phases%length !-------------------------------------------------------------------------------------------------- @@ -666,80 +644,6 @@ pure function constitutive_initialFi(ipc, ip, el) end function constitutive_initialFi -!-------------------------------------------------------------------------------------------------- -!> @brief returns the 2nd Piola-Kirchhoff stress tensor and its tangent with respect to -!> the elastic/intermediate deformation gradients depending on the selected elastic law -!! (so far no case switch because only Hooke is implemented) -!-------------------------------------------------------------------------------------------------- -subroutine constitutive_SandItsTangents(S, dS_dFe, dS_dFi, Fe, Fi, ipc, ip, el) - - integer, intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - real(pReal), intent(in), dimension(3,3) :: & - Fe, & !< elastic deformation gradient - Fi !< intermediate deformation gradient - real(pReal), intent(out), dimension(3,3) :: & - S !< 2nd Piola-Kirchhoff stress tensor - real(pReal), intent(out), dimension(3,3,3,3) :: & - dS_dFe, & !< derivative of 2nd P-K stress with respect to elastic deformation gradient - dS_dFi !< derivative of 2nd P-K stress with respect to intermediate deformation gradient - - call constitutive_hooke_SandItsTangents(S, dS_dFe, dS_dFi, Fe, Fi, ipc, ip, el) - - -end subroutine constitutive_SandItsTangents - - -!-------------------------------------------------------------------------------------------------- -!> @brief returns the 2nd Piola-Kirchhoff stress tensor and its tangent with respect to -!> the elastic and intermediate deformation gradients using Hooke's law -!-------------------------------------------------------------------------------------------------- -subroutine constitutive_hooke_SandItsTangents(S, dS_dFe, dS_dFi, & - Fe, Fi, ipc, ip, el) - - integer, intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - real(pReal), intent(in), dimension(3,3) :: & - Fe, & !< elastic deformation gradient - Fi !< intermediate deformation gradient - real(pReal), intent(out), dimension(3,3) :: & - S !< 2nd Piola-Kirchhoff stress tensor in lattice configuration - real(pReal), intent(out), dimension(3,3,3,3) :: & - dS_dFe, & !< derivative of 2nd P-K stress with respect to elastic deformation gradient - dS_dFi !< derivative of 2nd P-K stress with respect to intermediate deformation gradient - real(pReal), dimension(3,3) :: E - real(pReal), dimension(3,3,3,3) :: C - integer :: & - ho, & !< homogenization - d !< counter in degradation loop - integer :: & - i, j - - ho = material_homogenizationAt(el) - C = math_66toSym3333(constitutive_homogenizedC(ipc,ip,el)) - - DegradationLoop: do d = 1, phase_NstiffnessDegradations(material_phaseAt(ipc,el)) - degradationType: select case(phase_stiffnessDegradation(d,material_phaseAt(ipc,el))) - case (STIFFNESS_DEGRADATION_damage_ID) degradationType - C = C * damage(ho)%p(damageMapping(ho)%p(ip,el))**2 - end select degradationType - enddo DegradationLoop - - E = 0.5_pReal*(matmul(transpose(Fe),Fe)-math_I3) !< Green-Lagrange strain in unloaded configuration - S = math_mul3333xx33(C,matmul(matmul(transpose(Fi),E),Fi)) !< 2PK stress in lattice configuration in work conjugate with GL strain pulled back to lattice configuration - - do i =1, 3;do j=1,3 - dS_dFe(i,j,1:3,1:3) = matmul(Fe,matmul(matmul(Fi,C(i,j,1:3,1:3)),transpose(Fi))) !< dS_ij/dFe_kl = C_ijmn * Fi_lm * Fi_on * Fe_ko - dS_dFi(i,j,1:3,1:3) = 2.0_pReal*matmul(matmul(E,Fi),C(i,j,1:3,1:3)) !< dS_ij/dFi_kl = C_ijln * E_km * Fe_mn - enddo; enddo - -end subroutine constitutive_hooke_SandItsTangents - - !-------------------------------------------------------------------------------------------------- !> @brief contains the constitutive equation for calculating the rate of change of microstructure !-------------------------------------------------------------------------------------------------- diff --git a/src/constitutive_plastic.f90 b/src/constitutive_mech.f90 similarity index 76% rename from src/constitutive_plastic.f90 rename to src/constitutive_mech.f90 index bf6bc079e..074ef88fe 100644 --- a/src/constitutive_plastic.f90 +++ b/src/constitutive_mech.f90 @@ -1,7 +1,7 @@ !---------------------------------------------------------------------------------------------------- !> @brief internal microstructure state for all plasticity constitutive models !---------------------------------------------------------------------------------------------------- -submodule(constitutive) constitutive_plastic +submodule(constitutive) constitutive_mech interface @@ -191,17 +191,60 @@ contains !-------------------------------------------------------------------------------------------------- -!> @brief Initialize constitutive models for plasticity +!> @brief Initialize mechanical field related constitutive models +!> @details Initialize elasticity, plasticity and stiffness degradation models. !-------------------------------------------------------------------------------------------------- -module subroutine plastic_init +module subroutine mech_init - integer :: p - class(tNode), pointer :: phases + integer :: & + p, & + stiffDegradationCtr + class(tNode), pointer :: & + phases, & + phase, & + mech, & + elastic, & + stiffDegradation - print'(/,a)', ' <<<+- constitutive_plastic init -+>>>' + print'(/,a)', ' <<<+- constitutive_mech init -+>>>' +!------------------------------------------------------------------------------------------------- +! initialize elasticity (hooke) !ToDO: Maybe move to elastic submodule along with function homogenizedC? phases => config_material%get('phase') + allocate(phase_elasticity(phases%length), source = ELASTICITY_undefined_ID) + allocate(phase_elasticityInstance(phases%length), source = 0) + allocate(phase_NstiffnessDegradations(phases%length),source=0) + do p = 1, phases%length + phase => phases%get(p) + mech => phase%get('mech') + elastic => mech%get('elasticity') + if(elastic%get_asString('type') == 'hooke') then + phase_elasticity(p) = ELASTICITY_HOOKE_ID + else + call IO_error(200,ext_msg=elastic%get_asString('type')) + endif + stiffDegradation => mech%get('stiffness_degradation',defaultVal=emptyList) ! check for stiffness degradation mechanisms + phase_NstiffnessDegradations(p) = stiffDegradation%length + enddo + + allocate(phase_stiffnessDegradation(maxval(phase_NstiffnessDegradations),phases%length), & + source=STIFFNESS_DEGRADATION_undefined_ID) + + if(maxVal(phase_NstiffnessDegradations)/=0) then + do p = 1, phases%length + phase => phases%get(p) + mech => phase%get('mech') + stiffDegradation => mech%get('stiffness_degradation',defaultVal=emptyList) + do stiffDegradationCtr = 1, stiffDegradation%length + if(stiffDegradation%get_asString(stiffDegradationCtr) == 'damage') & + phase_stiffnessDegradation(stiffDegradationCtr,p) = STIFFNESS_DEGRADATION_damage_ID + enddo + enddo + endif + + +! initialize plasticity allocate(plasticState(phases%length)) allocate(phase_plasticity(phases%length),source = PLASTICITY_undefined_ID) allocate(phase_plasticityInstance(phases%length),source = 0) @@ -216,11 +259,11 @@ module subroutine plastic_init where(plastic_nonlocal_init()) phase_plasticity = PLASTICITY_NONLOCAL_ID do p = 1, phases%length + phase_elasticityInstance(p) = count(phase_elasticity(1:p) == phase_elasticity(p)) phase_plasticityInstance(p) = count(phase_plasticity(1:p) == phase_plasticity(p)) enddo - -end subroutine plastic_init +end subroutine mech_init !-------------------------------------------------------------------------------------------------- @@ -234,6 +277,7 @@ module function plastic_active(plastic_label) result(active_plastic) class(tNode), pointer :: & phases, & phase, & + mech, & pl integer :: p @@ -241,13 +285,62 @@ module function plastic_active(plastic_label) result(active_plastic) allocate(active_plastic(phases%length), source = .false. ) do p = 1, phases%length phase => phases%get(p) - pl => phase%get('plasticity') + mech => phase%get('mech') + pl => mech%get('plasticity') if(pl%get_asString('type') == plastic_label) active_plastic(p) = .true. enddo end function plastic_active +!-------------------------------------------------------------------------------------------------- +!> @brief returns the 2nd Piola-Kirchhoff stress tensor and its tangent with respect to +!> the elastic and intermediate deformation gradients using Hooke's law +!-------------------------------------------------------------------------------------------------- +module subroutine constitutive_hooke_SandItsTangents(S, dS_dFe, dS_dFi, & + Fe, Fi, ipc, ip, el) + + integer, intent(in) :: & + ipc, & !< component-ID of integration point + ip, & !< integration point + el !< element + real(pReal), intent(in), dimension(3,3) :: & + Fe, & !< elastic deformation gradient + Fi !< intermediate deformation gradient + real(pReal), intent(out), dimension(3,3) :: & + S !< 2nd Piola-Kirchhoff stress tensor in lattice configuration + real(pReal), intent(out), dimension(3,3,3,3) :: & + dS_dFe, & !< derivative of 2nd P-K stress with respect to elastic deformation gradient + dS_dFi !< derivative of 2nd P-K stress with respect to intermediate deformation gradient + real(pReal), dimension(3,3) :: E + real(pReal), dimension(3,3,3,3) :: C + integer :: & + ho, & !< homogenization + d !< counter in degradation loop + integer :: & + i, j + + ho = material_homogenizationAt(el) + C = math_66toSym3333(constitutive_homogenizedC(ipc,ip,el)) + + DegradationLoop: do d = 1, phase_NstiffnessDegradations(material_phaseAt(ipc,el)) + degradationType: select case(phase_stiffnessDegradation(d,material_phaseAt(ipc,el))) + case (STIFFNESS_DEGRADATION_damage_ID) degradationType + C = C * damage(ho)%p(damageMapping(ho)%p(ip,el))**2 + end select degradationType + enddo DegradationLoop + + E = 0.5_pReal*(matmul(transpose(Fe),Fe)-math_I3) !< Green-Lagrange strain in unloaded configuration + S = math_mul3333xx33(C,matmul(matmul(transpose(Fi),E),Fi)) !< 2PK stress in lattice configuration in work conjugate with GL strain pulled back to lattice configuration + + do i =1, 3;do j=1,3 + dS_dFe(i,j,1:3,1:3) = matmul(Fe,matmul(matmul(Fi,C(i,j,1:3,1:3)),transpose(Fi))) !< dS_ij/dFe_kl = C_ijmn * Fi_lm * Fi_on * Fe_ko + dS_dFi(i,j,1:3,1:3) = 2.0_pReal*matmul(matmul(E,Fi),C(i,j,1:3,1:3)) !< dS_ij/dFi_kl = C_ijln * E_km * Fe_mn + enddo; enddo + +end subroutine constitutive_hooke_SandItsTangents + + !-------------------------------------------------------------------------------------------------- !> @brief calls microstructure function of the different plasticity constitutive models !-------------------------------------------------------------------------------------------------- @@ -395,6 +488,5 @@ module subroutine plastic_results end subroutine plastic_results - -end submodule constitutive_plastic +end submodule constitutive_mech diff --git a/src/constitutive_plastic_disloTungsten.f90 b/src/constitutive_plastic_disloTungsten.f90 index aef3bef89..adaa36ee7 100644 --- a/src/constitutive_plastic_disloTungsten.f90 +++ b/src/constitutive_plastic_disloTungsten.f90 @@ -5,7 +5,7 @@ !> @author Martin Diehl, Max-Planck-Institut für Eisenforschung GmbH !> @brief crystal plasticity model for bcc metals, especially Tungsten !-------------------------------------------------------------------------------------------------- -submodule(constitutive:constitutive_plastic) plastic_disloTungsten +submodule(constitutive:constitutive_mech) plastic_disloTungsten real(pReal), parameter :: & kB = 1.38e-23_pReal !< Boltzmann constant in J/Kelvin @@ -94,6 +94,7 @@ module function plastic_disloTungsten_init() result(myPlasticity) class(tNode), pointer :: & phases, & phase, & + mech, & pl print'(/,a)', ' <<<+- plastic_dislotungsten init -+>>>' @@ -115,14 +116,14 @@ module function plastic_disloTungsten_init() result(myPlasticity) i = 0 do p = 1, phases%length phase => phases%get(p) - + mech => phase%get('mech') if(.not. myPlasticity(p)) cycle i = i + 1 associate(prm => param(i), & dot => dotState(i), & stt => state(i), & dst => dependentState(i)) - pl => phase%get('plasticity') + pl => mech%get('plasticity') #if defined (__GFORTRAN__) prm%output = output_asStrings(pl) diff --git a/src/constitutive_plastic_dislotwin.f90 b/src/constitutive_plastic_dislotwin.f90 index 30527e301..2bc2b1176 100644 --- a/src/constitutive_plastic_dislotwin.f90 +++ b/src/constitutive_plastic_dislotwin.f90 @@ -7,7 +7,7 @@ !> @brief material subroutine incoprorating dislocation and twinning physics !> @details to be done !-------------------------------------------------------------------------------------------------- -submodule(constitutive:constitutive_plastic) plastic_dislotwin +submodule(constitutive:constitutive_mech) plastic_dislotwin real(pReal), parameter :: & kB = 1.38e-23_pReal !< Boltzmann constant in J/Kelvin @@ -141,6 +141,7 @@ module function plastic_dislotwin_init() result(myPlasticity) class(tNode), pointer :: & phases, & phase, & + mech, & pl print'(/,a)', ' <<<+- plastic_dislotwin init -+>>>' @@ -168,14 +169,14 @@ module function plastic_dislotwin_init() result(myPlasticity) i = 0 do p = 1, phases%length phase => phases%get(p) - + mech => phase%get('mech') if(.not. myPlasticity(p)) cycle i = i + 1 associate(prm => param(i), & dot => dotState(i), & stt => state(i), & dst => dependentState(i)) - pl => phase%get('plasticity') + pl => mech%get('plasticity') #if defined (__GFORTRAN__) prm%output = output_asStrings(pl) diff --git a/src/constitutive_plastic_isotropic.f90 b/src/constitutive_plastic_isotropic.f90 index db418663f..4bbd5187e 100644 --- a/src/constitutive_plastic_isotropic.f90 +++ b/src/constitutive_plastic_isotropic.f90 @@ -7,7 +7,7 @@ !! resolving the stress on the slip systems. Will give the response of phenopowerlaw for an !! untextured polycrystal !-------------------------------------------------------------------------------------------------- -submodule(constitutive:constitutive_plastic) plastic_isotropic +submodule(constitutive:constitutive_mech) plastic_isotropic type :: tParameters real(pReal) :: & @@ -65,6 +65,7 @@ module function plastic_isotropic_init() result(myPlasticity) class(tNode), pointer :: & phases, & phase, & + mech, & pl print'(/,a)', ' <<<+- plastic_isotropic init -+>>>' @@ -85,13 +86,13 @@ module function plastic_isotropic_init() result(myPlasticity) i = 0 do p = 1, phases%length phase => phases%get(p) - + mech => phase%get('mech') if(.not. myPlasticity(p)) cycle i = i + 1 associate(prm => param(i), & dot => dotState(i), & stt => state(i)) - pl => phase%get('plasticity') + pl => mech%get('plasticity') #if defined (__GFORTRAN__) diff --git a/src/constitutive_plastic_kinehardening.f90 b/src/constitutive_plastic_kinehardening.f90 index 3faf7dc41..7dbd51597 100644 --- a/src/constitutive_plastic_kinehardening.f90 +++ b/src/constitutive_plastic_kinehardening.f90 @@ -5,7 +5,7 @@ !> @brief Phenomenological crystal plasticity using a power law formulation for the shear rates !! and a Voce-type kinematic hardening rule !-------------------------------------------------------------------------------------------------- -submodule(constitutive:constitutive_plastic) plastic_kinehardening +submodule(constitutive:constitutive_mech) plastic_kinehardening type :: tParameters real(pReal) :: & @@ -77,6 +77,7 @@ module function plastic_kinehardening_init() result(myPlasticity) class(tNode), pointer :: & phases, & phase, & + mech, & pl print'(/,a)', ' <<<+- plastic_kinehardening init -+>>>' @@ -95,14 +96,14 @@ module function plastic_kinehardening_init() result(myPlasticity) i = 0 do p = 1, phases%length phase => phases%get(p) - + mech => phase%get('mech') if(.not. myPlasticity(p)) cycle i = i + 1 associate(prm => param(i), & dot => dotState(i), & dlt => deltaState(i), & stt => state(i)) - pl => phase%get('plasticity') + pl => mech%get('plasticity') #if defined (__GFORTRAN__) prm%output = output_asStrings(pl) diff --git a/src/constitutive_plastic_none.f90 b/src/constitutive_plastic_none.f90 index 923ae354a..6164ab29f 100644 --- a/src/constitutive_plastic_none.f90 +++ b/src/constitutive_plastic_none.f90 @@ -4,7 +4,7 @@ !> @author Martin Diehl, Max-Planck-Institut für Eisenforschung GmbH !> @brief Dummy plasticity for purely elastic material !-------------------------------------------------------------------------------------------------- -submodule(constitutive:constitutive_plastic) plastic_none +submodule(constitutive:constitutive_mech) plastic_none contains @@ -22,6 +22,7 @@ module function plastic_none_init() result(myPlasticity) class(tNode), pointer :: & phases, & phase, & + mech, & pl print'(/,a)', ' <<<+- plastic_none init -+>>>' @@ -30,7 +31,8 @@ module function plastic_none_init() result(myPlasticity) allocate(myPlasticity(phases%length), source = .false.) do p = 1, phases%length phase => phases%get(p) - pl => phase%get('plasticity') + mech => phase%get('mech') + pl => mech%get ('plasticity') if(pl%get_asString('type') == 'none') myPlasticity(p) = .true. enddo diff --git a/src/constitutive_plastic_nonlocal.f90 b/src/constitutive_plastic_nonlocal.f90 index 472415ba9..8aab40fc8 100644 --- a/src/constitutive_plastic_nonlocal.f90 +++ b/src/constitutive_plastic_nonlocal.f90 @@ -4,7 +4,7 @@ !> @author Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH !> @brief material subroutine for plasticity including dislocation flux !-------------------------------------------------------------------------------------------------- -submodule(constitutive:constitutive_plastic) plastic_nonlocal +submodule(constitutive:constitutive_mech) plastic_nonlocal use geometry_plastic_nonlocal, only: & nIPneighbors => geometry_plastic_nonlocal_nIPneighbors, & IPneighborhood => geometry_plastic_nonlocal_IPneighborhood, & @@ -183,6 +183,7 @@ module function plastic_nonlocal_init() result(myPlasticity) class(tNode), pointer :: & phases, & phase, & + mech, & pl print'(/,a)', ' <<<+- plastic_nonlocal init -+>>>' @@ -212,7 +213,7 @@ module function plastic_nonlocal_init() result(myPlasticity) i = 0 do p = 1, phases%length phase => phases%get(p) - + mech => phase%get('mech') if(.not. myPlasticity(p)) cycle i = i + 1 associate(prm => param(i), & @@ -221,7 +222,7 @@ module function plastic_nonlocal_init() result(myPlasticity) st0 => state0(i), & del => deltaState(i), & dst => microstructure(i)) - pl => phase%get('plasticity') + pl => mech%get('plasticity') phase_localPlasticity(p) = .not. pl%contains('nonlocal') diff --git a/src/constitutive_plastic_phenopowerlaw.f90 b/src/constitutive_plastic_phenopowerlaw.f90 index 72fa0e9e6..747dd6615 100644 --- a/src/constitutive_plastic_phenopowerlaw.f90 +++ b/src/constitutive_plastic_phenopowerlaw.f90 @@ -4,7 +4,7 @@ !> @author Martin Diehl, Max-Planck-Institut für Eisenforschung GmbH !> @brief phenomenological crystal plasticity formulation using a powerlaw fitting !-------------------------------------------------------------------------------------------------- -submodule(constitutive:constitutive_plastic) plastic_phenopowerlaw +submodule(constitutive:constitutive_mech) plastic_phenopowerlaw type :: tParameters real(pReal) :: & @@ -86,6 +86,7 @@ module function plastic_phenopowerlaw_init() result(myPlasticity) class(tNode), pointer :: & phases, & phase, & + mech, & pl print'(/,a)', ' <<<+- plastic_phenopowerlaw init -+>>>' @@ -103,13 +104,13 @@ module function plastic_phenopowerlaw_init() result(myPlasticity) i = 0 do p = 1, phases%length phase => phases%get(p) - + mech => phase%get('mech') if(.not. myPlasticity(p)) cycle i = i + 1 associate(prm => param(i), & dot => dotState(i), & stt => state(i)) - pl => phase%get('plasticity') + pl => mech%get('plasticity') !-------------------------------------------------------------------------------------------------- ! slip related parameters diff --git a/src/crystallite.f90 b/src/crystallite.f90 index c9ef97e32..2315fcd77 100644 --- a/src/crystallite.f90 +++ b/src/crystallite.f90 @@ -150,7 +150,7 @@ subroutine crystallite_init debug_crystallite, & ! pointer to debug options for crystallite phases, & phase, & - generic_param + mech print'(/,a)', ' <<<+- crystallite init -+>>>' @@ -240,11 +240,11 @@ subroutine crystallite_init allocate(output_constituent(phases%length)) do c = 1, phases%length phase => phases%get(c) - generic_param => phase%get('generic',defaultVal = emptyDict) + mech => phase%get('mech',defaultVal = emptyDict) #if defined(__GFORTRAN__) - output_constituent(c)%label = output_asStrings(generic_param) + output_constituent(c)%label = output_asStrings(mech) #else - output_constituent(c)%label = generic_param%get_asStrings('output',defaultVal=emptyStringArray) + output_constituent(c)%label = mech%get_asStrings('output',defaultVal=emptyStringArray) #endif enddo @@ -736,7 +736,7 @@ subroutine crystallite_results integer :: p,o real(pReal), allocatable, dimension(:,:,:) :: selected_tensors type(rotation), allocatable, dimension(:) :: selected_rotations - character(len=pStringLen) :: group,structureLabel + character(len=:), allocatable :: group,structureLabel do p=1,size(material_name_phase) group = trim('current/constituent')//'/'//trim(material_name_phase(p))//'/generic' diff --git a/src/grid/discretization_grid.f90 b/src/grid/discretization_grid.f90 index 84223e0c8..bb6c6210d 100644 --- a/src/grid/discretization_grid.f90 +++ b/src/grid/discretization_grid.f90 @@ -84,6 +84,8 @@ subroutine discretization_grid_init(restart) PETSC_COMM_WORLD, & z, & ! domain grid size along z z_offset) ! domain grid offset along z + if(z==0_C_INTPTR_T) call IO_error(894, ext_msg='Cannot distribute MPI processes') + grid3 = int(z) grid3Offset = int(z_offset) size3 = geomSize(3)*real(grid3,pReal) /real(grid(3),pReal) diff --git a/src/grid/grid_damage_spectral.f90 b/src/grid/grid_damage_spectral.f90 index 7e529fc68..4c014f3c0 100644 --- a/src/grid/grid_damage_spectral.f90 +++ b/src/grid/grid_damage_spectral.f90 @@ -95,10 +95,10 @@ subroutine grid_damage_spectral_init !-------------------------------------------------------------------------------------------------- ! set default and user defined options for PETSc - call PETScOptionsInsertString(PETSC_NULL_OPTIONS,'-damage_snes_type newtonls -damage_snes_mf & + call PetscOptionsInsertString(PETSC_NULL_OPTIONS,'-damage_snes_type newtonls -damage_snes_mf & &-damage_snes_ksp_ew -damage_ksp_type fgmres',ierr) CHKERRQ(ierr) - call PETScOptionsInsertString(PETSC_NULL_OPTIONS,num_grid%get_asString('petsc_options',defaultVal=''),ierr) + call PetscOptionsInsertString(PETSC_NULL_OPTIONS,num_grid%get_asString('petsc_options',defaultVal=''),ierr) CHKERRQ(ierr) !-------------------------------------------------------------------------------------------------- diff --git a/src/grid/grid_mech_FEM.f90 b/src/grid/grid_mech_FEM.f90 index bf3d7752d..7d0830f67 100644 --- a/src/grid/grid_mech_FEM.f90 +++ b/src/grid/grid_mech_FEM.f90 @@ -13,6 +13,7 @@ module grid_mech_FEM use prec use parallelization use DAMASK_interface + use IO use HDF5_utilities use math use spectral_utilities @@ -141,10 +142,10 @@ subroutine grid_mech_FEM_init !-------------------------------------------------------------------------------------------------- ! set default and user defined options for PETSc - call PETScOptionsInsertString(PETSC_NULL_OPTIONS,'-mech_snes_type newtonls -mech_ksp_type fgmres & + call PetscOptionsInsertString(PETSC_NULL_OPTIONS,'-mech_snes_type newtonls -mech_ksp_type fgmres & &-mech_ksp_max_it 25 -mech_pc_type ml -mech_mg_levels_ksp_type chebyshev',ierr) CHKERRQ(ierr) - call PETScOptionsInsertString(PETSC_NULL_OPTIONS,num_grid%get_asString('petsc_options',defaultVal=''),ierr) + call PetscOptionsInsertString(PETSC_NULL_OPTIONS,num_grid%get_asString('petsc_options',defaultVal=''),ierr) CHKERRQ(ierr) !-------------------------------------------------------------------------------------------------- diff --git a/src/grid/grid_mech_spectral_basic.f90 b/src/grid/grid_mech_spectral_basic.f90 index ec6c3a540..8677a998f 100644 --- a/src/grid/grid_mech_spectral_basic.f90 +++ b/src/grid/grid_mech_spectral_basic.f90 @@ -13,6 +13,7 @@ module grid_mech_spectral_basic use prec use parallelization use DAMASK_interface + use IO use HDF5_utilities use math use spectral_utilities @@ -140,9 +141,9 @@ subroutine grid_mech_spectral_basic_init !-------------------------------------------------------------------------------------------------- ! set default and user defined options for PETSc - call PETScOptionsInsertString(PETSC_NULL_OPTIONS,'-mech_snes_type ngmres',ierr) + call PetscOptionsInsertString(PETSC_NULL_OPTIONS,'-mech_snes_type ngmres',ierr) CHKERRQ(ierr) - call PETScOptionsInsertString(PETSC_NULL_OPTIONS,num_grid%get_asString('petsc_options',defaultVal=''),ierr) + call PetscOptionsInsertString(PETSC_NULL_OPTIONS,num_grid%get_asString('petsc_options',defaultVal=''),ierr) CHKERRQ(ierr) !-------------------------------------------------------------------------------------------------- diff --git a/src/grid/grid_mech_spectral_polarisation.f90 b/src/grid/grid_mech_spectral_polarisation.f90 index 8f9ea81b3..ca92f62f4 100644 --- a/src/grid/grid_mech_spectral_polarisation.f90 +++ b/src/grid/grid_mech_spectral_polarisation.f90 @@ -13,6 +13,7 @@ module grid_mech_spectral_polarisation use prec use parallelization use DAMASK_interface + use IO use HDF5_utilities use math use spectral_utilities @@ -158,9 +159,9 @@ subroutine grid_mech_spectral_polarisation_init !-------------------------------------------------------------------------------------------------- ! set default and user defined options for PETSc - call PETScOptionsInsertString(PETSC_NULL_OPTIONS,'-mech_snes_type ngmres',ierr) + call PetscOptionsInsertString(PETSC_NULL_OPTIONS,'-mech_snes_type ngmres',ierr) CHKERRQ(ierr) - call PETScOptionsInsertString(PETSC_NULL_OPTIONS,num_grid%get_asString('petsc_options',defaultVal=''),ierr) + call PetscOptionsInsertString(PETSC_NULL_OPTIONS,num_grid%get_asString('petsc_options',defaultVal=''),ierr) CHKERRQ(ierr) !-------------------------------------------------------------------------------------------------- diff --git a/src/grid/grid_thermal_spectral.f90 b/src/grid/grid_thermal_spectral.f90 index b4f9acddb..68a1c5ed1 100644 --- a/src/grid/grid_thermal_spectral.f90 +++ b/src/grid/grid_thermal_spectral.f90 @@ -89,9 +89,9 @@ subroutine grid_thermal_spectral_init !-------------------------------------------------------------------------------------------------- ! set default and user defined options for PETSc - call PETScOptionsInsertString(PETSC_NULL_OPTIONS,'-thermal_snes_type ngmres',ierr) + call PetscOptionsInsertString(PETSC_NULL_OPTIONS,'-thermal_snes_type ngmres',ierr) CHKERRQ(ierr) - call PETScOptionsInsertString(PETSC_NULL_OPTIONS,num_grid%get_asString('petsc_options',defaultVal=''),ierr) + call PetscOptionsInsertString(PETSC_NULL_OPTIONS,num_grid%get_asString('petsc_options',defaultVal=''),ierr) CHKERRQ(ierr) !-------------------------------------------------------------------------------------------------- diff --git a/src/grid/spectral_utilities.f90 b/src/grid/spectral_utilities.f90 index fddd1885f..36ab99e2c 100644 --- a/src/grid/spectral_utilities.f90 +++ b/src/grid/spectral_utilities.f90 @@ -214,11 +214,11 @@ subroutine spectral_utilities_init num_grid => config_numerics%get('grid',defaultVal=emptyDict) - call PETScOptionsClear(PETSC_NULL_OPTIONS,ierr) + call PetscOptionsClear(PETSC_NULL_OPTIONS,ierr) CHKERRQ(ierr) - if(debugPETSc) call PETScOptionsInsertString(PETSC_NULL_OPTIONS,trim(PETSCDEBUG),ierr) + if(debugPETSc) call PetscOptionsInsertString(PETSC_NULL_OPTIONS,trim(PETSCDEBUG),ierr) CHKERRQ(ierr) - call PETScOptionsInsertString(PETSC_NULL_OPTIONS,& + call PetscOptionsInsertString(PETSC_NULL_OPTIONS,& num_grid%get_asString('petsc_options',defaultVal=''),ierr) CHKERRQ(ierr) @@ -313,12 +313,12 @@ subroutine spectral_utilities_init tensorSize, FFTW_MPI_DEFAULT_BLOCK, FFTW_MPI_DEFAULT_BLOCK, &! no. of transforms, default iblock and oblock tensorField_real, tensorField_fourier, & ! input data, output data PETSC_COMM_WORLD, FFTW_planner_flag) ! use all processors, planer precision - if (.not. C_ASSOCIATED(planTensorForth)) call IO_error(810, ext_msg='planTensorForth') + if (.not. C_ASSOCIATED(planTensorForth)) error stop 'FFTW error' planTensorBack = fftw_mpi_plan_many_dft_c2r(3, [gridFFTW(3),gridFFTW(2),gridFFTW(1)], & ! dimension, logical length in each dimension in reversed order tensorSize, FFTW_MPI_DEFAULT_BLOCK, FFTW_MPI_DEFAULT_BLOCK, &! no. of transforms, default iblock and oblock tensorField_fourier,tensorField_real, & ! input data, output data PETSC_COMM_WORLD, FFTW_planner_flag) ! all processors, planer precision - if (.not. C_ASSOCIATED(planTensorBack)) call IO_error(810, ext_msg='planTensorBack') + if (.not. C_ASSOCIATED(planTensorBack)) error stop 'FFTW error' !-------------------------------------------------------------------------------------------------- ! vector MPI fftw plans @@ -326,12 +326,12 @@ subroutine spectral_utilities_init vecSize, FFTW_MPI_DEFAULT_BLOCK, FFTW_MPI_DEFAULT_BLOCK,&! no. of transforms, default iblock and oblock vectorField_real, vectorField_fourier, & ! input data, output data PETSC_COMM_WORLD, FFTW_planner_flag) ! use all processors, planer precision - if (.not. C_ASSOCIATED(planVectorForth)) call IO_error(810, ext_msg='planVectorForth') + if (.not. C_ASSOCIATED(planVectorForth)) error stop 'FFTW error' planVectorBack = fftw_mpi_plan_many_dft_c2r(3, [gridFFTW(3),gridFFTW(2),gridFFTW(1)], & ! dimension, logical length in each dimension in reversed order vecSize, FFTW_MPI_DEFAULT_BLOCK, FFTW_MPI_DEFAULT_BLOCK, & ! no. of transforms, default iblock and oblock vectorField_fourier,vectorField_real, & ! input data, output data PETSC_COMM_WORLD, FFTW_planner_flag) ! all processors, planer precision - if (.not. C_ASSOCIATED(planVectorBack)) call IO_error(810, ext_msg='planVectorBack') + if (.not. C_ASSOCIATED(planVectorBack)) error stop 'FFTW error' !-------------------------------------------------------------------------------------------------- ! scalar MPI fftw plans @@ -339,12 +339,12 @@ subroutine spectral_utilities_init scalarSize, FFTW_MPI_DEFAULT_BLOCK, FFTW_MPI_DEFAULT_BLOCK, &! no. of transforms, default iblock and oblock scalarField_real, scalarField_fourier, & ! input data, output data PETSC_COMM_WORLD, FFTW_planner_flag) ! use all processors, planer precision - if (.not. C_ASSOCIATED(planScalarForth)) call IO_error(810, ext_msg='planScalarForth') + if (.not. C_ASSOCIATED(planScalarForth)) error stop 'FFTW error' planScalarBack = fftw_mpi_plan_many_dft_c2r(3, [gridFFTW(3),gridFFTW(2),gridFFTW(1)], & ! dimension, logical length in each dimension in reversed order, no. of transforms scalarSize, FFTW_MPI_DEFAULT_BLOCK, FFTW_MPI_DEFAULT_BLOCK, &! no. of transforms, default iblock and oblock scalarField_fourier,scalarField_real, & ! input data, output data PETSC_COMM_WORLD, FFTW_planner_flag) ! use all processors, planer precision - if (.not. C_ASSOCIATED(planScalarBack)) call IO_error(810, ext_msg='planScalarBack') + if (.not. C_ASSOCIATED(planScalarBack)) error stop 'FFTW error' !-------------------------------------------------------------------------------------------------- ! calculation of discrete angular frequencies, ordered as in FFTW (wrap around) @@ -603,10 +603,9 @@ real(pReal) function utilities_divergenceRMS() enddo; enddo if(grid(1) == 1) utilities_divergenceRMS = utilities_divergenceRMS * 0.5_pReal ! counted twice in case of grid(1) == 1 call MPI_Allreduce(MPI_IN_PLACE,utilities_divergenceRMS,1,MPI_DOUBLE,MPI_SUM,PETSC_COMM_WORLD,ierr) - if(ierr /=0) call IO_error(894, ext_msg='utilities_divergenceRMS') + if(ierr /=0) error stop 'MPI error' utilities_divergenceRMS = sqrt(utilities_divergenceRMS) * wgt ! RMS in real space calculated with Parsevals theorem from Fourier space - end function utilities_divergenceRMS @@ -664,7 +663,7 @@ real(pReal) function utilities_curlRMS() enddo; enddo call MPI_Allreduce(MPI_IN_PLACE,utilities_curlRMS,1,MPI_DOUBLE,MPI_SUM,PETSC_COMM_WORLD,ierr) - if(ierr /=0) call IO_error(894, ext_msg='utilities_curlRMS') + if(ierr /=0) error stop 'MPI error' utilities_curlRMS = sqrt(utilities_curlRMS) * wgt if(grid(1) == 1) utilities_curlRMS = utilities_curlRMS * 0.5_pReal ! counted twice in case of grid(1) == 1 @@ -713,7 +712,6 @@ function utilities_maskedCompliance(rot_BC,mask_stress,C) allocate(s_reduced,mold = c_reduced) call math_invert(s_reduced, errmatinv, c_reduced) ! invert reduced stiffness if (any(IEEE_is_NaN(s_reduced))) errmatinv = .true. - if (errmatinv) call IO_error(error_ID=400,ext_msg='utilities_maskedCompliance') !-------------------------------------------------------------------------------------------------- ! check if inversion was successful @@ -725,7 +723,7 @@ function utilities_maskedCompliance(rot_BC,mask_stress,C) write(IO_STDOUT,trim(formatString),advance='no') ' C * S (load) ', & transpose(matmul(c_reduced,s_reduced)) write(IO_STDOUT,trim(formatString),advance='no') ' S (load) ', transpose(s_reduced) - if(errmatinv) call IO_error(error_ID=400,ext_msg='utilities_maskedCompliance') + if(errmatinv) error stop 'matrix inversion error' endif temp99_real = reshape(unpack(reshape(s_reduced,[size_reduced**2]),reshape(mask,[81]),0.0_pReal),[9,9]) else @@ -857,20 +855,21 @@ subroutine utilities_constitutiveResponse(P,P_av,C_volAvg,C_minmaxAvg,& valueAndRank = [dPdF_norm_max,real(worldrank,pReal)] call MPI_Allreduce(MPI_IN_PLACE,valueAndRank,1, MPI_2DOUBLE_PRECISION, MPI_MAXLOC, PETSC_COMM_WORLD, ierr) - if (ierr /= 0) call IO_error(894, ext_msg='MPI_Allreduce max') + if (ierr /= 0) error stop 'MPI error' call MPI_Bcast(dPdF_max,81,MPI_DOUBLE,int(valueAndRank(2)),PETSC_COMM_WORLD, ierr) - if (ierr /= 0) call IO_error(894, ext_msg='MPI_Bcast max') + if (ierr /= 0) error stop 'MPI error' valueAndRank = [dPdF_norm_min,real(worldrank,pReal)] call MPI_Allreduce(MPI_IN_PLACE,valueAndRank,1, MPI_2DOUBLE_PRECISION, MPI_MINLOC, PETSC_COMM_WORLD, ierr) - if (ierr /= 0) call IO_error(894, ext_msg='MPI_Allreduce min') + if (ierr /= 0) error stop 'MPI error' call MPI_Bcast(dPdF_min,81,MPI_DOUBLE,int(valueAndRank(2)),PETSC_COMM_WORLD, ierr) - if (ierr /= 0) call IO_error(894, ext_msg='MPI_Bcast min') + if (ierr /= 0) error stop 'MPI error' C_minmaxAvg = 0.5_pReal*(dPdF_max + dPdF_min) C_volAvg = sum(sum(homogenization_dPdF,dim=6),dim=5) call MPI_Allreduce(MPI_IN_PLACE,C_volAvg,81,MPI_DOUBLE,MPI_SUM,PETSC_COMM_WORLD,ierr) + if (ierr /= 0) error stop 'MPI error' C_volAvg = C_volAvg * wgt @@ -1035,7 +1034,7 @@ subroutine utilities_updateCoords(F) ! average F if (grid3Offset == 0) Favg = real(tensorField_fourier(1:3,1:3,1,1,1),pReal)*wgt call MPI_Bcast(Favg,9,MPI_DOUBLE,0,PETSC_COMM_WORLD,ierr) - if(ierr /=0) call IO_error(894, ext_msg='update_IPcoords/MPI_Bcast') + if(ierr /=0) error stop 'MPI error' !-------------------------------------------------------------------------------------------------- ! pad cell center fluctuations along z-direction (needed when running MPI simulation) @@ -1046,19 +1045,19 @@ subroutine utilities_updateCoords(F) ! send bottom layer to process below call MPI_Isend(IPfluct_padded(:,:,:,2), c,MPI_DOUBLE,rank_b,0,PETSC_COMM_WORLD,r,ierr) - if(ierr /=0) call IO_error(894, ext_msg='update_IPcoords/MPI_Isend') + if(ierr /=0) error stop 'MPI error' call MPI_Irecv(IPfluct_padded(:,:,:,grid3+2),c,MPI_DOUBLE,rank_t,0,PETSC_COMM_WORLD,r,ierr) - if(ierr /=0) call IO_error(894, ext_msg='update_IPcoords/MPI_Irecv') + if(ierr /=0) error stop 'MPI error' call MPI_Wait(r,s,ierr) - if(ierr /=0) call IO_error(894, ext_msg='update_IPcoords/MPI_Wait') + if(ierr /=0) error stop 'MPI error' ! send top layer to process above call MPI_Isend(IPfluct_padded(:,:,:,grid3+1),c,MPI_DOUBLE,rank_t,0,PETSC_COMM_WORLD,r,ierr) - if(ierr /=0) call IO_error(894, ext_msg='update_IPcoords/MPI_Isend') + if(ierr /=0) error stop 'MPI error' call MPI_Irecv(IPfluct_padded(:,:,:,1), c,MPI_DOUBLE,rank_b,0,PETSC_COMM_WORLD,r,ierr) - if(ierr /=0) call IO_error(894, ext_msg='update_IPcoords/MPI_Irecv') + if(ierr /=0) error stop 'MPI error' call MPI_Wait(r,s,ierr) - if(ierr /=0) call IO_error(894, ext_msg='update_IPcoords/MPI_Wait') + if(ierr /=0) error stop 'MPI error' !-------------------------------------------------------------------------------------------------- ! calculate nodal displacements diff --git a/src/homogenization.f90 b/src/homogenization.f90 index 02f1d3bf0..33af8ff95 100644 --- a/src/homogenization.f90 +++ b/src/homogenization.f90 @@ -529,7 +529,7 @@ subroutine homogenization_results material_homogenization_type => homogenization_type integer :: p - character(len=pStringLen) :: group_base,group + character(len=:), allocatable :: group_base,group !real(pReal), dimension(:,:,:), allocatable :: temp diff --git a/src/kinematics_cleavage_opening.f90 b/src/kinematics_cleavage_opening.f90 index 44bbcb4f4..66bce6a92 100644 --- a/src/kinematics_cleavage_opening.f90 +++ b/src/kinematics_cleavage_opening.f90 @@ -41,7 +41,6 @@ module function kinematics_cleavage_opening_init(kinematics_length) result(myKin class(tNode), pointer :: & phases, & phase, & - pl, & kinematics, & kinematic_type @@ -58,8 +57,7 @@ module function kinematics_cleavage_opening_init(kinematics_length) result(myKin do p = 1, phases%length if(any(myKinematics(:,p))) kinematics_cleavage_opening_instance(p) = count(myKinematics(:,1:p)) - phase => phases%get(p) - pl => phase%get('plasticity') + phase => phases%get(p) if(count(myKinematics(:,p)) == 0) cycle kinematics => phase%get('kinematics') do k = 1, kinematics%length diff --git a/src/kinematics_slipplane_opening.f90 b/src/kinematics_slipplane_opening.f90 index ea8f51427..7e45a7a05 100644 --- a/src/kinematics_slipplane_opening.f90 +++ b/src/kinematics_slipplane_opening.f90 @@ -44,6 +44,7 @@ module function kinematics_slipplane_opening_init(kinematics_length) result(myKi class(tNode), pointer :: & phases, & phase, & + mech, & pl, & kinematics, & kinematic_type @@ -61,8 +62,9 @@ module function kinematics_slipplane_opening_init(kinematics_length) result(myKi do p = 1, phases%length if(any(myKinematics(:,p))) kinematics_slipplane_opening_instance(p) = count(myKinematics(:,1:p)) - phase => phases%get(p) - pl => phase%get('plasticity') + phase => phases%get(p) + mech => phase%get('mech') + pl => mech%get('plasticity') if(count(myKinematics(:,p)) == 0) cycle kinematics => phase%get('kinematics') do k = 1, kinematics%length diff --git a/src/kinematics_thermal_expansion.f90 b/src/kinematics_thermal_expansion.f90 index 4afde82e3..2b8b04d85 100644 --- a/src/kinematics_thermal_expansion.f90 +++ b/src/kinematics_thermal_expansion.f90 @@ -34,7 +34,6 @@ module function kinematics_thermal_expansion_init(kinematics_length) result(myKi class(tNode), pointer :: & phases, & phase, & - pl, & kinematics, & kinematic_type @@ -52,7 +51,6 @@ module function kinematics_thermal_expansion_init(kinematics_length) result(myKi do p = 1, phases%length if(any(myKinematics(:,p))) kinematics_thermal_expansion_instance(p) = count(myKinematics(:,1:p)) phase => phases%get(p) - pl => phase%get('plasticity') if(count(myKinematics(:,p)) == 0) cycle kinematics => phase%get('kinematics') do k = 1, kinematics%length diff --git a/src/lattice.f90 b/src/lattice.f90 index 78b3894c0..08385eac7 100644 --- a/src/lattice.f90 +++ b/src/lattice.f90 @@ -455,6 +455,7 @@ subroutine lattice_init class(tNode), pointer :: & phases, & phase, & + mech, & elasticity print'(/,a)', ' <<<+- lattice init -+>>>'; flush(IO_STDOUT) @@ -475,7 +476,8 @@ subroutine lattice_init do p = 1, phases%length phase => phases%get(p) - elasticity => phase%get('elasticity') + mech => phase%get('mech') + elasticity => mech%get('elasticity') lattice_C66(1,1,p) = elasticity%get_asFloat('C_11') lattice_C66(1,2,p) = elasticity%get_asFloat('C_12') @@ -586,9 +588,6 @@ function lattice_characteristicShear_Twin(Ntwin,structure,CoverA) result(charact 4 & ],[HEX_NTWIN]) ! indicator to formulas below - if (len_trim(structure) /= 3) & - call IO_error(137,ext_msg='lattice_characteristicShear_Twin: '//trim(structure)) - a = 0 myFamilies: do f = 1,size(Ntwin,1) mySystems: do s = 1,Ntwin(f) @@ -634,9 +633,6 @@ function lattice_C66_twin(Ntwin,C66,structure,CoverA) type(rotation) :: R integer :: i - if (len_trim(structure) /= 3) & - call IO_error(137,ext_msg='lattice_C66_twin: '//trim(structure)) - select case(structure) case('fcc') coordinateSystem = buildCoordinateSystem(Ntwin,FCC_NSLIPSYSTEM,FCC_SYSTEMTWIN,& @@ -964,9 +960,6 @@ function lattice_interaction_SlipBySlip(Nslip,interactionValues,structure) resul ],shape(BCT_INTERACTIONSLIPSLIP)) - if (len_trim(structure) /= 3) & - call IO_error(137,ext_msg='lattice_interaction_SlipBySlip: '//trim(structure)) - select case(structure) case('fcc') interactionTypes = FCC_INTERACTIONSLIPSLIP @@ -1068,9 +1061,6 @@ function lattice_interaction_TwinByTwin(Ntwin,interactionValues,structure) resul 20,20,20,20,20,20, 19,19,19,19,19,19, 18,18,18,18,18,18, 17,17,17,17,17,16 & ],shape(HEX_INTERACTIONTWINTWIN)) !< Twin-twin interaction types for hex - if (len_trim(structure) /= 3) & - call IO_error(137,ext_msg='lattice_interaction_TwinByTwin: '//trim(structure)) - select case(structure) case('fcc') interactionTypes = FCC_INTERACTIONTWINTWIN @@ -1120,9 +1110,6 @@ function lattice_interaction_TransByTrans(Ntrans,interactionValues,structure) re 2,2,2,2,2,2,2,2,2,1,1,1 & ],shape(FCC_INTERACTIONTRANSTRANS)) !< Trans-trans interaction types for fcc - if (len_trim(structure) /= 3) & - call IO_error(137,ext_msg='lattice_interaction_TransByTrans: '//trim(structure)) - if(structure == 'fcc') then interactionTypes = FCC_INTERACTIONTRANSTRANS NtransMax = FCC_NTRANSSYSTEM @@ -1250,9 +1237,6 @@ function lattice_interaction_SlipByTwin(Nslip,Ntwin,interactionValues,structure) ! ],shape(HEX_INTERACTIONSLIPTWIN)) !< Slip-twin interaction types for hex - if (len_trim(structure) /= 3) & - call IO_error(137,ext_msg='lattice_interaction_SlipByTwin: '//trim(structure)) - select case(structure) case('fcc') interactionTypes = FCC_INTERACTIONSLIPTWIN @@ -1314,9 +1298,6 @@ function lattice_interaction_SlipByTrans(Nslip,Ntrans,interactionValues,structur 4,4,4,4,4,4,4,4,4,4,4,4 & ],shape(FCC_INTERACTIONSLIPTRANS)) !< Slip-trans interaction types for fcc - if (len_trim(structure) /= 3) & - call IO_error(137,ext_msg='lattice_interaction_SlipByTrans: '//trim(structure)) - select case(structure) case('fcc') interactionTypes = FCC_INTERACTIONSLIPTRANS @@ -1384,9 +1365,6 @@ function lattice_interaction_TwinBySlip(Ntwin,Nslip,interactionValues,structure) 4, 4, 4, 8, 8, 8, 12,12,12, 16,16,16,16,16,16, 20,20,20,20,20,20,20,20,20,20,20,20, 24,24,24,24,24,24 & ],shape(HEX_INTERACTIONTWINSLIP)) !< Twin-slip interaction types for hex - if (len_trim(structure) /= 3) & - call IO_error(137,ext_msg='lattice_interaction_TwinBySlip: '//trim(structure)) - select case(structure) case('fcc') interactionTypes = FCC_INTERACTIONTWINSLIP @@ -1425,9 +1403,6 @@ function lattice_SchmidMatrix_slip(Nslip,structure,cOverA) result(SchmidMatrix) integer, dimension(:), allocatable :: NslipMax integer :: i - if (len_trim(structure) /= 3) & - call IO_error(137,ext_msg='lattice_SchmidMatrix_slip: '//trim(structure)) - select case(structure) case('fcc') NslipMax = FCC_NSLIPSYSTEM @@ -1478,9 +1453,6 @@ function lattice_SchmidMatrix_twin(Ntwin,structure,cOverA) result(SchmidMatrix) integer, dimension(:), allocatable :: NtwinMax integer :: i - if (len_trim(structure) /= 3) & - call IO_error(137,ext_msg='lattice_SchmidMatrix_twin: '//trim(structure)) - select case(structure) case('fcc') NtwinMax = FCC_NTWINSYSTEM @@ -1558,9 +1530,6 @@ function lattice_SchmidMatrix_cleavage(Ncleavage,structure,cOverA) result(Schmid integer, dimension(:), allocatable :: NcleavageMax integer :: i - if (len_trim(structure) /= 3) & - call IO_error(137,ext_msg='lattice_SchmidMatrix_cleavage: '//trim(structure)) - select case(structure) case('ort') NcleavageMax = ORT_NCLEAVAGESYSTEM @@ -1660,9 +1629,6 @@ function lattice_labels_slip(Nslip,structure) result(labels) real(pReal), dimension(:,:), allocatable :: slipSystems integer, dimension(:), allocatable :: NslipMax - if (len_trim(structure) /= 3) & - call IO_error(137,ext_msg='lattice_labels_slip: '//trim(structure)) - select case(structure) case('fcc') NslipMax = FCC_NSLIPSYSTEM @@ -1704,9 +1670,6 @@ function lattice_applyLatticeSymmetry33(T,structure) result(T_sym) T_sym = 0.0_pReal - if (len_trim(structure) /= 3) & - call IO_error(137,ext_msg='lattice_applyLatticeSymmetry33: '//trim(structure)) - select case(structure) case('iso','fcc','bcc') do k=1,3 @@ -1742,9 +1705,6 @@ function applyLatticeSymmetryC66(C66,structure) result(C66_sym) C66_sym = 0.0_pReal - if (len_trim(structure) /= 3) & - call IO_error(137,ext_msg='applyLatticeSymmetryC66: '//trim(structure)) - select case(structure) case ('iso') do k=1,3 @@ -1822,9 +1782,6 @@ function lattice_labels_twin(Ntwin,structure) result(labels) real(pReal), dimension(:,:), allocatable :: twinSystems integer, dimension(:), allocatable :: NtwinMax - if (len_trim(structure) /= 3) & - call IO_error(137,ext_msg='lattice_labels_twin: '//trim(structure)) - select case(structure) case('fcc') NtwinMax = FCC_NTWINSYSTEM @@ -1911,9 +1868,6 @@ function coordinateSystem_slip(Nslip,structure,cOverA) result(coordinateSystem) real(pReal), dimension(:,:), allocatable :: slipSystems integer, dimension(:), allocatable :: NslipMax - if (len_trim(structure) /= 3) & - call IO_error(137,ext_msg='coordinateSystem_slip: '//trim(structure)) - select case(structure) case('fcc') NslipMax = FCC_NSLIPSYSTEM @@ -2255,11 +2209,11 @@ function equivalent_nu(C,assumption) result(nu) / 9.0_pReal elseif(IO_lc(assumption) == 'reuss') then call math_invert(S,error,C) - if(error) call IO_error(0) + if(error) error stop 'matrix inversion failed' K = 1.0_pReal & / (S(1,1)+S(2,2)+S(3,3) +2.0_pReal*(S(1,2)+S(2,3)+S(1,3))) else - call IO_error(0) + error stop 'invalid assumption' K = 0.0_pReal endif @@ -2287,11 +2241,11 @@ function equivalent_mu(C,assumption) result(mu) / 15.0_pReal elseif(IO_lc(assumption) == 'reuss') then call math_invert(S,error,C) - if(error) call IO_error(0) + if(error) error stop 'matrix inversion failed' mu = 15.0_pReal & / (4.0_pReal*(S(1,1)+S(2,2)+S(3,3)) -4.0_pReal*(S(1,2)+S(2,3)+S(1,3)) +3.0_pReal*(S(4,4)+S(5,5)+S(6,6))) else - call IO_error(0) + error stop 'invalid assumption' mu = 0.0_pReal endif diff --git a/src/math.f90 b/src/math.f90 index 163f4df6a..1fc9bd7eb 100644 --- a/src/math.f90 +++ b/src/math.f90 @@ -499,7 +499,7 @@ function math_invSym3333(A) call dgetrf(6,6,temp66,6,ipiv6,ierr_i) call dgetri(6,temp66,6,ipiv6,work,size(work,1),ierr_f) if (ierr_i /= 0 .or. ierr_f /= 0) then - call IO_error(400, ext_msg = 'math_invSym3333') + error stop 'matrix inversion error' else math_invSym3333 = math_66toSym3333(temp66) endif @@ -1200,8 +1200,8 @@ subroutine selfTest if(any(dNeq(math_exp33(math_I3,0),math_I3))) & error stop 'math_exp33(math_I3,1)' - if(any(dNeq(math_exp33(math_I3,256),exp(1.0_pReal)*math_I3))) & - error stop 'math_exp33(math_I3,256)' + if(any(dNeq(math_exp33(math_I3,128),exp(1.0_pReal)*math_I3))) & + error stop 'math_exp33(math_I3,128)' call random_number(v9) if(any(dNeq(math_33to9(math_9to33(v9)),v9))) & diff --git a/src/parallelization.f90 b/src/parallelization.f90 index fb50a1a23..b7d7c50a8 100644 --- a/src/parallelization.f90 +++ b/src/parallelization.f90 @@ -50,10 +50,17 @@ subroutine parallelization_init if (threadLevel>>' diff --git a/src/prec.f90 b/src/prec.f90 index b2866a4f4..738775e3b 100644 --- a/src/prec.f90 +++ b/src/prec.f90 @@ -93,7 +93,8 @@ subroutine prec_init print'(a,i19)', ' Maximum value: ',huge(0) 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)', ' 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) call selfTest diff --git a/src/quit.f90 b/src/quit.f90 index 5c421c86a..26dc23bac 100644 --- a/src/quit.f90 +++ b/src/quit.f90 @@ -23,7 +23,7 @@ subroutine quit(stop_id) call h5close_f(error) if (error /= 0) write(6,'(a,i5)') ' Error in h5close_f ',error - call PETScFinalize(ierr) + call PetscFinalize(ierr) CHKERRQ(ierr) #ifdef _OPENMP diff --git a/src/results.f90 b/src/results.f90 index 1ccc6bfab..eac894c11 100644 --- a/src/results.f90 +++ b/src/results.f90 @@ -7,6 +7,7 @@ module results use DAMASK_interface use parallelization + use IO use rotations use HDF5_utilities #ifdef PETSc @@ -535,33 +536,46 @@ subroutine results_mapping_constituent(phaseAt,memberAtLocal,label) integer(SIZE_T) :: type_size_string, type_size_int - integer :: ierr, i + integer :: hdferr, ierr, i !--------------------------------------------------------------------------------------------------- ! compound type: name of phase section + position/index within results array - call h5tcopy_f(H5T_NATIVE_CHARACTER, dt_id, ierr) - call h5tset_size_f(dt_id, int(len(label(1)),SIZE_T), ierr) - call h5tget_size_f(dt_id, type_size_string, ierr) + call h5tcopy_f(H5T_NATIVE_CHARACTER, dt_id, hdferr) + if(hdferr < 0) error stop 'HDF5 error' + call h5tset_size_f(dt_id, int(len(label(1)),SIZE_T), hdferr) + if(hdferr < 0) error stop 'HDF5 error' + call h5tget_size_f(dt_id, type_size_string, hdferr) + if(hdferr < 0) error stop 'HDF5 error' - call h5tget_size_f(H5T_NATIVE_INTEGER, type_size_int, ierr) + call h5tget_size_f(H5T_NATIVE_INTEGER, type_size_int, hdferr) + if(hdferr < 0) error stop 'HDF5 error' - call h5tcreate_f(H5T_COMPOUND_F, type_size_string + type_size_int, dtype_id, ierr) - call h5tinsert_f(dtype_id, "Name", 0_SIZE_T, dt_id,ierr) - call h5tinsert_f(dtype_id, "Position", type_size_string, H5T_NATIVE_INTEGER, ierr) + call h5tcreate_f(H5T_COMPOUND_F, type_size_string + type_size_int, dtype_id, hdferr) + if(hdferr < 0) error stop 'HDF5 error' + call h5tinsert_f(dtype_id, "Name", 0_SIZE_T, dt_id,hdferr) + if(hdferr < 0) error stop 'HDF5 error' + call h5tinsert_f(dtype_id, "Position", type_size_string, H5T_NATIVE_INTEGER, hdferr) + if(hdferr < 0) error stop 'HDF5 error' !-------------------------------------------------------------------------------------------------- ! create memory types for each component of the compound type - call h5tcreate_f(H5T_COMPOUND_F, type_size_string, name_id, ierr) - call h5tinsert_f(name_id, "Name", 0_SIZE_T, dt_id, ierr) + call h5tcreate_f(H5T_COMPOUND_F, type_size_string, name_id, hdferr) + if(hdferr < 0) error stop 'HDF5 error' + call h5tinsert_f(name_id, "Name", 0_SIZE_T, dt_id, hdferr) + if(hdferr < 0) error stop 'HDF5 error' - call h5tcreate_f(H5T_COMPOUND_F, type_size_int, position_id, ierr) - call h5tinsert_f(position_id, "Position", 0_SIZE_T, H5T_NATIVE_INTEGER, ierr) + call h5tcreate_f(H5T_COMPOUND_F, type_size_int, position_id, hdferr) + if(hdferr < 0) error stop 'HDF5 error' + call h5tinsert_f(position_id, "Position", 0_SIZE_T, H5T_NATIVE_INTEGER, hdferr) + if(hdferr < 0) error stop 'HDF5 error' - call h5tclose_f(dt_id, ierr) + call h5tclose_f(dt_id, hdferr) + if(hdferr < 0) error stop 'HDF5 error' !-------------------------------------------------------------------------------------------------- ! prepare MPI communication (transparent for non-MPI runs) - call h5pcreate_f(H5P_DATASET_XFER_F, plist_id, ierr) + call h5pcreate_f(H5P_DATASET_XFER_F, plist_id, hdferr) + if(hdferr < 0) error stop 'HDF5 error' memberOffset = 0 do i=1, size(label) memberOffset(i,worldrank) = count(phaseAt == i)*size(memberAtLocal,2) ! number of points/instance of this process @@ -572,14 +586,14 @@ subroutine results_mapping_constituent(phaseAt,memberAtLocal,label) !-------------------------------------------------------------------------------------------------- ! MPI settings and communication #ifdef PETSc - call h5pset_dxpl_mpio_f(plist_id, H5FD_MPIO_COLLECTIVE_F, ierr) - if (ierr < 0) call IO_error(1,ext_msg='results_mapping_constituent: h5pset_dxpl_mpio_f') + call h5pset_dxpl_mpio_f(plist_id, H5FD_MPIO_COLLECTIVE_F, hdferr) + if(hdferr < 0) error stop 'HDF5 error' call MPI_allreduce(MPI_IN_PLACE,writeSize,worldsize,MPI_INT,MPI_SUM,PETSC_COMM_WORLD,ierr) ! get output at each process - if (ierr /= 0) call IO_error(894,ext_msg='results_mapping_constituent: MPI_allreduce/writeSize') + if(ierr /= 0) error stop 'MPI error' call MPI_allreduce(MPI_IN_PLACE,memberOffset,size(memberOffset),MPI_INT,MPI_SUM,PETSC_COMM_WORLD,ierr)! get offset at each process - if (ierr /= 0) call IO_error(894,ext_msg='results_mapping_constituent: MPI_allreduce/memberOffset') + if(ierr /= 0) error stop 'MPI error' #endif myShape = int([size(phaseAt,1),writeSize(worldrank)], HSIZE_T) @@ -588,14 +602,14 @@ subroutine results_mapping_constituent(phaseAt,memberAtLocal,label) !-------------------------------------------------------------------------------------------------- ! create dataspace in memory (local shape = hyperslab) and in file (global shape) - call h5screate_simple_f(2,myShape,memspace_id,ierr,myShape) - if (ierr < 0) call IO_error(1,ext_msg='results_mapping_constituent: h5screate_simple_f/memspace_id') + call h5screate_simple_f(2,myShape,memspace_id,hdferr,myShape) + if(hdferr < 0) error stop 'HDF5 error' - call h5screate_simple_f(2,totalShape,filespace_id,ierr,totalShape) - if (ierr < 0) call IO_error(1,ext_msg='results_mapping_constituent: h5screate_simple_f/filespace_id') + call h5screate_simple_f(2,totalShape,filespace_id,hdferr,totalShape) + if(hdferr < 0) error stop 'HDF5 error' - call h5sselect_hyperslab_f(filespace_id, H5S_SELECT_SET_F, myOffset, myShape, ierr) - if (ierr < 0) call IO_error(1,ext_msg='results_mapping_constituent: h5sselect_hyperslab_f') + call h5sselect_hyperslab_f(filespace_id, H5S_SELECT_SET_F, myOffset, myShape, hdferr) + if(hdferr < 0) error stop 'HDF5 error' !--------------------------------------------------------------------------------------------------- ! expand phaseAt to consider IPs (is not stored per IP) @@ -611,29 +625,36 @@ subroutine results_mapping_constituent(phaseAt,memberAtLocal,label) !-------------------------------------------------------------------------------------------------- ! write the components of the compound type individually - call h5pset_preserve_f(plist_id, .TRUE., ierr) + call h5pset_preserve_f(plist_id, .TRUE., hdferr) + if(hdferr < 0) error stop 'HDF5 error' loc_id = results_openGroup('/mapping') - call h5dcreate_f(loc_id, 'phase', dtype_id, filespace_id, dset_id, ierr) - if (ierr < 0) call IO_error(1,ext_msg='results_mapping_constituent: h5dcreate_f') + call h5dcreate_f(loc_id, 'phase', dtype_id, filespace_id, dset_id, hdferr) + if(hdferr < 0) error stop 'HDF5 error' call h5dwrite_f(dset_id, name_id, reshape(label(pack(phaseAtMaterialpoint,.true.)),myShape), & - myShape, ierr, file_space_id = filespace_id, mem_space_id = memspace_id, xfer_prp = plist_id) - if (ierr < 0) call IO_error(1,ext_msg='results_mapping_constituent: h5dwrite_f/name_id') + myShape, hdferr, file_space_id = filespace_id, mem_space_id = memspace_id, xfer_prp = plist_id) + if(hdferr < 0) error stop 'HDF5 error' call h5dwrite_f(dset_id, position_id, reshape(pack(memberAtGlobal,.true.),myShape), & - myShape, ierr, file_space_id = filespace_id, mem_space_id = memspace_id, xfer_prp = plist_id) - if (ierr < 0) call IO_error(1,ext_msg='results_mapping_constituent: h5dwrite_f/position_id') + myShape, hdferr, file_space_id = filespace_id, mem_space_id = memspace_id, xfer_prp = plist_id) + if(hdferr < 0) error stop 'HDF5 error' !-------------------------------------------------------------------------------------------------- ! close all call HDF5_closeGroup(loc_id) - call h5pclose_f(plist_id, ierr) - call h5sclose_f(filespace_id, ierr) - call h5sclose_f(memspace_id, ierr) - call h5dclose_f(dset_id, ierr) - call h5tclose_f(dtype_id, ierr) - call h5tclose_f(name_id, ierr) - call h5tclose_f(position_id, ierr) + call h5pclose_f(plist_id, hdferr) + if(hdferr < 0) error stop 'HDF5 error' + call h5sclose_f(filespace_id, hdferr) + if(hdferr < 0) error stop 'HDF5 error' + call h5sclose_f(memspace_id, hdferr) + if(hdferr < 0) error stop 'HDF5 error' + call h5dclose_f(dset_id, hdferr) + if(hdferr < 0) error stop 'HDF5 error' + call h5tclose_f(dtype_id, hdferr) + if(hdferr < 0) error stop 'HDF5 error' + call h5tclose_f(name_id, hdferr) + if(hdferr < 0) error stop 'HDF5 error' + call h5tclose_f(position_id, hdferr) ! for backward compatibility call results_setLink('/mapping/phase','/mapping/cellResults/constituent') @@ -673,51 +694,64 @@ subroutine results_mapping_homogenization(homogenizationAt,memberAtLocal,label) integer(SIZE_T) :: type_size_string, type_size_int - integer :: ierr, i + integer :: hdferr, ierr, i !--------------------------------------------------------------------------------------------------- ! compound type: name of phase section + position/index within results array - call h5tcopy_f(H5T_NATIVE_CHARACTER, dt_id, ierr) - call h5tset_size_f(dt_id, int(len(label(1)),SIZE_T), ierr) - call h5tget_size_f(dt_id, type_size_string, ierr) + call h5tcopy_f(H5T_NATIVE_CHARACTER, dt_id, hdferr) + if(hdferr < 0) error stop 'HDF5 error' + call h5tset_size_f(dt_id, int(len(label(1)),SIZE_T), hdferr) + if(hdferr < 0) error stop 'HDF5 error' + call h5tget_size_f(dt_id, type_size_string, hdferr) + if(hdferr < 0) error stop 'HDF5 error' - call h5tget_size_f(H5T_NATIVE_INTEGER, type_size_int, ierr) + call h5tget_size_f(H5T_NATIVE_INTEGER, type_size_int, hdferr) + if(hdferr < 0) error stop 'HDF5 error' - call h5tcreate_f(H5T_COMPOUND_F, type_size_string + type_size_int, dtype_id, ierr) - call h5tinsert_f(dtype_id, "Name", 0_SIZE_T, dt_id,ierr) - call h5tinsert_f(dtype_id, "Position", type_size_string, H5T_NATIVE_INTEGER, ierr) + call h5tcreate_f(H5T_COMPOUND_F, type_size_string + type_size_int, dtype_id, hdferr) + if(hdferr < 0) error stop 'HDF5 error' + call h5tinsert_f(dtype_id, "Name", 0_SIZE_T, dt_id,hdferr) + if(hdferr < 0) error stop 'HDF5 error' + call h5tinsert_f(dtype_id, "Position", type_size_string, H5T_NATIVE_INTEGER, hdferr) + if(hdferr < 0) error stop 'HDF5 error' !-------------------------------------------------------------------------------------------------- ! create memory types for each component of the compound type - call h5tcreate_f(H5T_COMPOUND_F, type_size_string, name_id, ierr) - call h5tinsert_f(name_id, "Name", 0_SIZE_T, dt_id, ierr) + call h5tcreate_f(H5T_COMPOUND_F, type_size_string, name_id, hdferr) + if(hdferr < 0) error stop 'HDF5 error' + call h5tinsert_f(name_id, "Name", 0_SIZE_T, dt_id, hdferr) + if(hdferr < 0) error stop 'HDF5 error' - call h5tcreate_f(H5T_COMPOUND_F, type_size_int, position_id, ierr) - call h5tinsert_f(position_id, "Position", 0_SIZE_T, H5T_NATIVE_INTEGER, ierr) + call h5tcreate_f(H5T_COMPOUND_F, type_size_int, position_id, hdferr) + if(hdferr < 0) error stop 'HDF5 error' + call h5tinsert_f(position_id, "Position", 0_SIZE_T, H5T_NATIVE_INTEGER, hdferr) + if(hdferr < 0) error stop 'HDF5 error' - call h5tclose_f(dt_id, ierr) + call h5tclose_f(dt_id, hdferr) + if(hdferr < 0) error stop 'HDF5 error' !-------------------------------------------------------------------------------------------------- ! prepare MPI communication (transparent for non-MPI runs) - call h5pcreate_f(H5P_DATASET_XFER_F, plist_id, ierr) + call h5pcreate_f(H5P_DATASET_XFER_F, plist_id, hdferr) + if(hdferr < 0) error stop 'HDF5 error' memberOffset = 0 do i=1, size(label) - memberOffset(i,worldrank) = count(homogenizationAt == i)*size(memberAtLocal,1) ! number of points/instance of this process + memberOffset(i,worldrank) = count(homogenizationAt == i)*size(memberAtLocal,1) ! number of points/instance of this process enddo writeSize = 0 - writeSize(worldrank) = size(memberAtLocal) ! total number of points by this process + writeSize(worldrank) = size(memberAtLocal) ! total number of points by this process !-------------------------------------------------------------------------------------------------- ! MPI settings and communication #ifdef PETSc - call h5pset_dxpl_mpio_f(plist_id, H5FD_MPIO_COLLECTIVE_F, ierr) - if (ierr < 0) call IO_error(1,ext_msg='results_mapping_homogenization: h5pset_dxpl_mpio_f') + call h5pset_dxpl_mpio_f(plist_id, H5FD_MPIO_COLLECTIVE_F, hdferr) + if(hdferr < 0) error stop 'HDF5 error' call MPI_allreduce(MPI_IN_PLACE,writeSize,worldsize,MPI_INT,MPI_SUM,PETSC_COMM_WORLD,ierr) ! get output at each process - if (ierr /= 0) call IO_error(894,ext_msg='results_mapping_homogenization: MPI_allreduce/writeSize') + if(ierr /= 0) error stop 'MPI error' call MPI_allreduce(MPI_IN_PLACE,memberOffset,size(memberOffset),MPI_INT,MPI_SUM,PETSC_COMM_WORLD,ierr)! get offset at each process - if (ierr /= 0) call IO_error(894,ext_msg='results_mapping_homogenization: MPI_allreduce/memberOffset') + if(ierr /= 0) error stop 'MPI error' #endif myShape = int([writeSize(worldrank)], HSIZE_T) @@ -726,14 +760,14 @@ subroutine results_mapping_homogenization(homogenizationAt,memberAtLocal,label) !-------------------------------------------------------------------------------------------------- ! create dataspace in memory (local shape = hyperslab) and in file (global shape) - call h5screate_simple_f(1,myShape,memspace_id,ierr,myShape) - if (ierr < 0) call IO_error(1,ext_msg='results_mapping_homogenization: h5screate_simple_f/memspace_id') + call h5screate_simple_f(1,myShape,memspace_id,hdferr,myShape) + if(hdferr < 0) error stop 'HDF5 error' - call h5screate_simple_f(1,totalShape,filespace_id,ierr,totalShape) - if (ierr < 0) call IO_error(1,ext_msg='results_mapping_homogenization: h5screate_simple_f/filespace_id') + call h5screate_simple_f(1,totalShape,filespace_id,hdferr,totalShape) + if(hdferr < 0) error stop 'HDF5 error' - call h5sselect_hyperslab_f(filespace_id, H5S_SELECT_SET_F, myOffset, myShape, ierr) - if (ierr < 0) call IO_error(1,ext_msg='results_mapping_homogenization: h5sselect_hyperslab_f') + call h5sselect_hyperslab_f(filespace_id, H5S_SELECT_SET_F, myOffset, myShape, hdferr) + if(hdferr < 0) error stop 'HDF5 error' !--------------------------------------------------------------------------------------------------- ! expand phaseAt to consider IPs (is not stored per IP) @@ -749,29 +783,36 @@ subroutine results_mapping_homogenization(homogenizationAt,memberAtLocal,label) !-------------------------------------------------------------------------------------------------- ! write the components of the compound type individually - call h5pset_preserve_f(plist_id, .TRUE., ierr) + call h5pset_preserve_f(plist_id, .TRUE., hdferr) loc_id = results_openGroup('/mapping') - call h5dcreate_f(loc_id, 'homogenization', dtype_id, filespace_id, dset_id, ierr) - if (ierr < 0) call IO_error(1,ext_msg='results_mapping_homogenization: h5dcreate_f') + call h5dcreate_f(loc_id, 'homogenization', dtype_id, filespace_id, dset_id, hdferr) + if(hdferr < 0) error stop 'HDF5 error' call h5dwrite_f(dset_id, name_id, reshape(label(pack(homogenizationAtMaterialpoint,.true.)),myShape), & - myShape, ierr, file_space_id = filespace_id, mem_space_id = memspace_id, xfer_prp = plist_id) - if (ierr < 0) call IO_error(1,ext_msg='results_mapping_homogenization: h5dwrite_f/name_id') + myShape, hdferr, file_space_id = filespace_id, mem_space_id = memspace_id, xfer_prp = plist_id) + if(hdferr < 0) error stop 'HDF5 error' call h5dwrite_f(dset_id, position_id, reshape(pack(memberAtGlobal,.true.),myShape), & - myShape, ierr, file_space_id = filespace_id, mem_space_id = memspace_id, xfer_prp = plist_id) - if (ierr < 0) call IO_error(1,ext_msg='results_mapping_homogenization: h5dwrite_f/position_id') + myShape, hdferr, file_space_id = filespace_id, mem_space_id = memspace_id, xfer_prp = plist_id) + if(hdferr < 0) error stop 'HDF5 error' !-------------------------------------------------------------------------------------------------- ! close all call HDF5_closeGroup(loc_id) - call h5pclose_f(plist_id, ierr) - call h5sclose_f(filespace_id, ierr) - call h5sclose_f(memspace_id, ierr) - call h5dclose_f(dset_id, ierr) - call h5tclose_f(dtype_id, ierr) - call h5tclose_f(name_id, ierr) - call h5tclose_f(position_id, ierr) + call h5pclose_f(plist_id, hdferr) + if(hdferr < 0) error stop 'HDF5 error' + call h5sclose_f(filespace_id, hdferr) + if(hdferr < 0) error stop 'HDF5 error' + call h5sclose_f(memspace_id, hdferr) + if(hdferr < 0) error stop 'HDF5 error' + call h5dclose_f(dset_id, hdferr) + if(hdferr < 0) error stop 'HDF5 error' + call h5tclose_f(dtype_id, hdferr) + if(hdferr < 0) error stop 'HDF5 error' + call h5tclose_f(name_id, hdferr) + if(hdferr < 0) error stop 'HDF5 error' + call h5tclose_f(position_id, hdferr) + if(hdferr < 0) error stop 'HDF5 error' ! for backward compatibility call results_setLink('/mapping/homogenization','/mapping/cellResults/materialpoint') @@ -793,263 +834,4 @@ character(len=24) function now() end function now - -!!-------------------------------------------------------------------------------------------------- -!!> @brief adds the backward mapping from spatial position and constituent ID to results -!!-------------------------------------------------------------------------------------------------- -!subroutine HDF5_backwardMappingPhase(material_phase,phasememberat,phase_name,dataspace_size,mpiOffset,mpiOffset_phase) - -! integer(pInt), intent(in), dimension(:,:,:) :: material_phase, phasememberat -! character(len=*), intent(in), dimension(:) :: phase_name -! integer(pInt), intent(in), dimension(:) :: dataspace_size, mpiOffset_phase -! integer(pInt), intent(in) :: mpiOffset - -! integer(pInt) :: hdferr, NmatPoints, Nconstituents, i, j -! integer(HID_T) :: mapping_id, dtype_id, dset_id, space_id, position_id, plist_id, memspace -! integer(SIZE_T) :: type_size - -! integer(pInt), dimension(:,:), allocatable :: arr - -! integer(HSIZE_T), dimension(1) :: counter -! integer(HSSIZE_T), dimension(1) :: fileOffset - -! character(len=64) :: phaseID - -! Nconstituents = size(phasememberat,1) -! NmatPoints = count(material_phase /=0)/Nconstituents - -! allocate(arr(2,NmatPoints*Nconstituents)) - -! do i=1, NmatPoints -! do j=Nconstituents-1, 0, -1 -! arr(1,Nconstituents*i-j) = i-1 -! enddo -! enddo -! arr(2,:) = pack(material_phase,material_phase/=0) - -! do i=1, size(phase_name) -! write(phaseID, '(i0)') i -! mapping_ID = results_openGroup('/current/constitutive/'//trim(phaseID)//'_'//phase_name(i)) -! NmatPoints = count(material_phase == i) - -!!-------------------------------------------------------------------------------------------------- -! ! create dataspace -! call h5screate_simple_f(1, int([dataspace_size(i)],HSIZE_T), space_id, hdferr, & -! int([dataspace_size(i)],HSIZE_T)) -! if (hdferr < 0) call IO_error(1,ext_msg='HDF5_writeBackwardMapping') - -!!-------------------------------------------------------------------------------------------------- -! ! compound type -! call h5tget_size_f(H5T_STD_I32LE, type_size, hdferr) -! call h5tcreate_f(H5T_COMPOUND_F, type_size, dtype_id, hdferr) -! if (hdferr < 0) call IO_error(1,ext_msg='HDF5_writeBackwardMapping: h5tcreate_f dtype_id') - -! call h5tinsert_f(dtype_id, "Position", 0_SIZE_T, H5T_STD_I32LE, hdferr) -! if (hdferr < 0) call IO_error(1,ext_msg='IO_backwardMappingPhase: h5tinsert_f 0') - -!!-------------------------------------------------------------------------------------------------- -! ! create Dataset -! call h5dcreate_f(mapping_id, 'mapGeometry', dtype_id, space_id, dset_id, hdferr) -! if (hdferr < 0) call IO_error(1,ext_msg='IO_backwardMappingPhase') - -!!-------------------------------------------------------------------------------------------------- -! ! Create memory types (one compound datatype for each member) -! call h5tcreate_f(H5T_COMPOUND_F, int(pInt,SIZE_T), position_id, hdferr) -! if (hdferr < 0) call IO_error(1,ext_msg='IO_backwardMappingPhase: h5tcreate_f position_id') -! call h5tinsert_f(position_id, "Position", 0_SIZE_T, H5T_STD_I32LE, hdferr) -! if (hdferr < 0) call IO_error(1,ext_msg='IO_backwardMappingPhase: h5tinsert_f position_id') - -!!-------------------------------------------------------------------------------------------------- -! ! Define and select hyperslabs -! counter = NmatPoints ! how big i am -! fileOffset = mpiOffset_phase(i) ! where i start to write my data - -! call h5screate_simple_f(1, counter, memspace, hdferr) -! if (hdferr < 0) call IO_error(1,ext_msg='IO_backwardMappingPhase: h5screate_simple_f') -! call h5dget_space_f(dset_id, space_id, hdferr) -! if (hdferr < 0) call IO_error(1,ext_msg='IO_backwardMappingPhase: h5dget_space_f') -! call h5sselect_hyperslab_f(space_id, H5S_SELECT_SET_F, fileOffset, counter, hdferr) -! if (hdferr < 0) call IO_error(1,ext_msg='IO_backwardMappingPhase: h5sselect_hyperslab_f') - -!!-------------------------------------------------------------------------------------------------- -! ! Create property list for collective dataset write -!#ifdef PETSc -! call h5pcreate_f(H5P_DATASET_XFER_F, plist_id, hdferr) -! if (hdferr < 0) call IO_error(1,ext_msg='IO_backwardMappingPhase: h5pcreate_f') -! call h5pset_dxpl_mpio_f(plist_id, H5FD_MPIO_COLLECTIVE_F, hdferr) -! if (hdferr < 0) call IO_error(1,ext_msg='IO_backwardMappingPhase: h5pset_dxpl_mpio_f') -!#endif - -!!-------------------------------------------------------------------------------------------------- -! ! write data by fields in the datatype. Fields order is not important. -! call h5dwrite_f(dset_id, position_id, pack(arr(1,:),arr(2,:)==i)+mpiOffset, int([dataspace_size(i)],HSIZE_T),& -! hdferr, file_space_id = space_id, mem_space_id = memspace, xfer_prp = plist_id) -! if (hdferr < 0) call IO_error(1,ext_msg='IO_backwardMappingPhase: h5dwrite_f instance_id') - -!!-------------------------------------------------------------------------------------------------- -! !close types, dataspaces -! call h5tclose_f(dtype_id, hdferr) -! if (hdferr < 0) call IO_error(1,ext_msg='IO_backwardMappingPhase: h5tclose_f dtype_id') -! call h5tclose_f(position_id, hdferr) -! if (hdferr < 0) call IO_error(1,ext_msg='IO_backwardMappingPhase: h5tclose_f position_id') -! call h5dclose_f(dset_id, hdferr) -! if (hdferr < 0) call IO_error(1,ext_msg='IO_backwardMappingPhase: h5dclose_f') -! call h5sclose_f(space_id, hdferr) -! if (hdferr < 0) call IO_error(1,ext_msg='IO_backwardMappingPhase: h5sclose_f space_id') -! call h5sclose_f(memspace, hdferr) -! if (hdferr < 0) call IO_error(1,ext_msg='IO_backwardMappingPhase: h5sclose_f memspace') -! call h5pclose_f(plist_id, hdferr) -! if (hdferr < 0) call IO_error(1,ext_msg='IO_backwardMappingPhase: h5pclose_f') -! call HDF5_closeGroup(mapping_ID) - -! enddo - -!end subroutine HDF5_backwardMappingPhase - - -!!-------------------------------------------------------------------------------------------------- -!!> @brief adds the backward mapping from spatial position and constituent ID to results -!!-------------------------------------------------------------------------------------------------- -!subroutine HDF5_backwardMappingHomog(material_homog,homogmemberat,homogenization_name,dataspace_size,mpiOffset,mpiOffset_homog) - -! integer(pInt), intent(in), dimension(:,:) :: material_homog, homogmemberat -! character(len=*), intent(in), dimension(:) :: homogenization_name -! integer(pInt), intent(in), dimension(:) :: dataspace_size, mpiOffset_homog -! integer(pInt), intent(in) :: mpiOffset - -! integer(pInt) :: hdferr, NmatPoints, i -! integer(HID_T) :: mapping_id, dtype_id, dset_id, space_id, position_id, plist_id, memspace -! integer(SIZE_T) :: type_size - -! integer(pInt), dimension(:,:), allocatable :: arr - -! integer(HSIZE_T), dimension(1) :: counter -! integer(HSSIZE_T), dimension(1) :: fileOffset - -! character(len=64) :: homogID - -! NmatPoints = count(material_homog /=0) -! allocate(arr(2,NmatPoints)) - -! arr(1,:) = (/(i, i=0,NmatPoints-1)/) -! arr(2,:) = pack(material_homog,material_homog/=0) - -! do i=1, size(homogenization_name) -! write(homogID, '(i0)') i -! mapping_ID = results_openGroup('/current/homogenization/'//trim(homogID)//'_'//homogenization_name(i)) - -!!-------------------------------------------------------------------------------------------------- -! ! create dataspace -! call h5screate_simple_f(1, int([dataspace_size(i)],HSIZE_T), space_id, hdferr, & -! int([dataspace_size(i)],HSIZE_T)) -! if (hdferr < 0) call IO_error(1,ext_msg='HDF5_writeBackwardMapping') - -!!-------------------------------------------------------------------------------------------------- -! ! compound type -! call h5tget_size_f(H5T_STD_I32LE, type_size, hdferr) -! call h5tcreate_f(H5T_COMPOUND_F, type_size, dtype_id, hdferr) -! if (hdferr < 0) call IO_error(1,ext_msg='HDF5_writeBackwardMapping: h5tcreate_f dtype_id') - -! call h5tinsert_f(dtype_id, "Position", 0_SIZE_T, H5T_STD_I32LE, hdferr) -! if (hdferr < 0) call IO_error(1,ext_msg='IO_backwardMappingHomog: h5tinsert_f 0') - -!!-------------------------------------------------------------------------------------------------- -! ! create Dataset -! call h5dcreate_f(mapping_id, 'mapGeometry', dtype_id, space_id, dset_id, hdferr) -! if (hdferr < 0) call IO_error(1,ext_msg='IO_backwardMappingHomog') - -!!-------------------------------------------------------------------------------------------------- -! ! Create memory types (one compound datatype for each member) -! call h5tcreate_f(H5T_COMPOUND_F, int(pInt,SIZE_T), position_id, hdferr) -! if (hdferr < 0) call IO_error(1,ext_msg='IO_backwardMappingHomog: h5tcreate_f position_id') -! call h5tinsert_f(position_id, "Position", 0_SIZE_T, H5T_STD_I32LE, hdferr) -! if (hdferr < 0) call IO_error(1,ext_msg='IO_backwardMappingHomog: h5tinsert_f position_id') - -!!-------------------------------------------------------------------------------------------------- -! ! Define and select hyperslabs -! counter = NmatPoints ! how big i am -! fileOffset = mpiOffset_homog(i) ! where i start to write my data - -! call h5screate_simple_f(1, counter, memspace, hdferr) -! if (hdferr < 0) call IO_error(1,ext_msg='IO_backwardMappingHomog: h5screate_simple_f') -! call h5dget_space_f(dset_id, space_id, hdferr) -! if (hdferr < 0) call IO_error(1,ext_msg='IO_backwardMappingHomog: h5dget_space_f') -! call h5sselect_hyperslab_f(space_id, H5S_SELECT_SET_F, fileOffset, counter, hdferr) -! if (hdferr < 0) call IO_error(1,ext_msg='IO_backwardMappingHomog: h5sselect_hyperslab_f') - -!!-------------------------------------------------------------------------------------------------- -! ! Create property list for collective dataset write -!#ifdef PETSc -! call h5pcreate_f(H5P_DATASET_XFER_F, plist_id, hdferr) -! if (hdferr < 0) call IO_error(1,ext_msg='IO_backwardMappingHomog: h5pcreate_f') -! call h5pset_dxpl_mpio_f(plist_id, H5FD_MPIO_COLLECTIVE_F, hdferr) -! if (hdferr < 0) call IO_error(1,ext_msg='IO_backwardMappingHomog: h5pset_dxpl_mpio_f') -!#endif - -!!-------------------------------------------------------------------------------------------------- -! ! write data by fields in the datatype. Fields order is not important. -! call h5dwrite_f(dset_id, position_id, pack(arr(1,:),arr(2,:)==i)+mpiOffset,int([dataspace_size(i)],HSIZE_T),& -! hdferr, file_space_id = space_id, mem_space_id = memspace, xfer_prp = plist_id) -! if (hdferr < 0) call IO_error(1,ext_msg='IO_backwardMappingHomog: h5dwrite_f instance_id') - -!!-------------------------------------------------------------------------------------------------- -! !close types, dataspaces -! call h5tclose_f(dtype_id, hdferr) -! if (hdferr < 0) call IO_error(1,ext_msg='IO_backwardMappingHomog: h5tclose_f dtype_id') -! call h5tclose_f(position_id, hdferr) -! if (hdferr < 0) call IO_error(1,ext_msg='IO_backwardMappingHomog: h5tclose_f position_id') -! call h5dclose_f(dset_id, hdferr) -! if (hdferr < 0) call IO_error(1,ext_msg='IO_backwardMappingHomog: h5dclose_f') -! call h5sclose_f(space_id, hdferr) -! if (hdferr < 0) call IO_error(1,ext_msg='IO_backwardMappingHomog: h5sclose_f space_id') -! call h5sclose_f(memspace, hdferr) -! if (hdferr < 0) call IO_error(1,ext_msg='IO_backwardMappingHomog: h5sclose_f memspace') -! call h5pclose_f(plist_id, hdferr) -! if (hdferr < 0) call IO_error(1,ext_msg='IO_backwardMappingHomog: h5pclose_f') -! call HDF5_closeGroup(mapping_ID) - -! enddo - -!end subroutine HDF5_backwardMappingHomog - - -!!-------------------------------------------------------------------------------------------------- -!!> @brief adds the unique cell to node mapping -!!-------------------------------------------------------------------------------------------------- -!subroutine HDF5_mappingCells(mapping) - -! integer(pInt), intent(in), dimension(:) :: mapping - -! integer :: hdferr, Nnodes -! integer(HID_T) :: mapping_id, dset_id, space_id - -! Nnodes=size(mapping) -! mapping_ID = results_openGroup("mapping") - -!!-------------------------------------------------------------------------------------------------- -!! create dataspace -! call h5screate_simple_f(1, int([Nnodes],HSIZE_T), space_id, hdferr, & -! int([Nnodes],HSIZE_T)) -! if (hdferr < 0) call IO_error(1,ext_msg='IO_mappingCells: h5screate_simple_f') - -!!-------------------------------------------------------------------------------------------------- -!! create Dataset -! call h5dcreate_f(mapping_id, "Cell",H5T_NATIVE_INTEGER, space_id, dset_id, hdferr) -! if (hdferr < 0) call IO_error(1,ext_msg='IO_mappingCells') - -!!-------------------------------------------------------------------------------------------------- -!! write data by fields in the datatype. Fields order is not important. -! call h5dwrite_f(dset_id, H5T_NATIVE_INTEGER, mapping, int([Nnodes],HSIZE_T), hdferr) -! if (hdferr < 0) call IO_error(1,ext_msg='IO_mappingCells: h5dwrite_f instance_id') - -!!-------------------------------------------------------------------------------------------------- -!!close types, dataspaces -! call h5dclose_f(dset_id, hdferr) -! if (hdferr < 0) call IO_error(1,ext_msg='IO_mappingConstitutive: h5dclose_f') -! call h5sclose_f(space_id, hdferr) -! if (hdferr < 0) call IO_error(1,ext_msg='IO_mappingConstitutive: h5sclose_f') -! call HDF5_closeGroup(mapping_ID) - -!end subroutine HDF5_mappingCells - end module results diff --git a/src/rotations.f90 b/src/rotations.f90 index ea4a8a9d8..888e73762 100644 --- a/src/rotations.f90 +++ b/src/rotations.f90 @@ -640,13 +640,13 @@ function om2ax(om) result(ax) ax(1:3) = [ 0.0_pReal, 0.0_pReal, 1.0_pReal ] else call dgeev('N','V',3,om_,3,Wr,Wi,devNull,3,VR,3,work,size(work,1),ierr) - if (ierr /= 0) call IO_error(401,ext_msg='Error in om2ax: DGEEV return not zero') + if (ierr /= 0) error stop 'LAPACK error' #if defined(__GFORTRAN__) && __GNUC__<9 || defined(__INTEL_COMPILER) && INTEL_COMPILER<1800 || defined(__PGI) i = maxloc(merge(1,0,cEq(cmplx(Wr,Wi,pReal),cmplx(1.0_pReal,0.0_pReal,pReal),tol=1.0e-14_pReal)),dim=1) #else i = findloc(cEq(cmplx(Wr,Wi,pReal),cmplx(1.0_pReal,0.0_pReal,pReal),tol=1.0e-14_pReal),.true.,dim=1) !find eigenvalue (1,0) #endif - if (i == 0) call IO_error(401,ext_msg='Error in om2ax Real: eigenvalue not found') + if (i == 0) error stop 'om2ax conversion failed' ax(1:3) = VR(1:3,i) where ( dNeq0([om(2,3)-om(3,2), om(3,1)-om(1,3), om(1,2)-om(2,1)])) & ax(1:3) = sign(ax(1:3),-P *[om(2,3)-om(3,2), om(3,1)-om(1,3), om(1,2)-om(2,1)]) diff --git a/src/source_damage_anisoDuctile.f90 b/src/source_damage_anisoDuctile.f90 index 2fdd46bb4..ffbb38d2a 100644 --- a/src/source_damage_anisoDuctile.f90 +++ b/src/source_damage_anisoDuctile.f90 @@ -36,6 +36,7 @@ module function source_damage_anisoDuctile_init(source_length) result(mySources) class(tNode), pointer :: & phases, & phase, & + mech, & pl, & sources, & src @@ -56,11 +57,12 @@ module function source_damage_anisoDuctile_init(source_length) result(mySources) allocate(source_damage_anisoDuctile_instance(phases%length), source=0) do p = 1, phases%length - phase => phases%get(p) + phase => phases%get(p) if(any(mySources(:,p))) source_damage_anisoDuctile_instance(p) = count(mySources(:,1:p)) if(count(mySources(:,p)) == 0) cycle + mech => phase%get('mech') + pl => mech%get('plasticity') sources => phase%get('source') - pl => phase%get('plasticity') do sourceOffset = 1, sources%length if(mySources(sourceOffset,p)) then source_damage_anisoDuctile_offset(p) = sourceOffset