Merge remote-tracking branch 'origin/development' into initial-temp

This commit is contained in:
Martin Diehl 2022-03-10 08:52:05 +01:00
commit e8383cec69
44 changed files with 735 additions and 732 deletions

View File

@ -5,7 +5,6 @@ stages:
- compile - compile
- fortran - fortran
- performance - performance
- deploy
- finalize - finalize
@ -212,14 +211,6 @@ grid_runtime:
- if [ ${CI_COMMIT_BRANCH} == development ]; then git commit -am ${CI_PIPELINE_ID}_${CI_COMMIT_SHA}; git push; fi - if [ ${CI_COMMIT_BRANCH} == development ]; then git commit -am ${CI_PIPELINE_ID}_${CI_COMMIT_SHA}; git push; fi
###################################################################################################
source_distribution:
stage: deploy
script:
- cd $(mktemp -d)
- ${CI_PROJECT_DIR}/PRIVATE/releasing/tar.xz/create.sh ${CI_PROJECT_DIR} ${CI_COMMIT_SHA}
################################################################################################### ###################################################################################################
update_revision: update_revision:
stage: finalize stage: finalize

@ -1 +1 @@
Subproject commit 68111b8fc3fb45f77d7471ae0f57961b4c77641d Subproject commit 17250a3a29f07af3c4d4e4083213d46efd534268

View File

@ -1,7 +1,7 @@
################################################################################################### ###################################################################################################
# GNU Compiler # GNU Compiler
################################################################################################### ###################################################################################################
if (CMAKE_Fortran_COMPILER_VERSION VERSION_LESS 8.0) if (CMAKE_Fortran_COMPILER_VERSION VERSION_LESS 9.0)
message (FATAL_ERROR "GCC Compiler version: ${CMAKE_Fortran_COMPILER_VERSION} not supported") message (FATAL_ERROR "GCC Compiler version: ${CMAKE_Fortran_COMPILER_VERSION} not supported")
endif () endif ()
@ -102,12 +102,11 @@ set (COMPILE_FLAGS "${COMPILE_FLAGS} -Wsuggest-attribute=pure")
set (COMPILE_FLAGS "${COMPILE_FLAGS} -Wsuggest-attribute=noreturn") set (COMPILE_FLAGS "${COMPILE_FLAGS} -Wsuggest-attribute=noreturn")
set (COMPILE_FLAGS "${COMPILE_FLAGS} -Wconversion-extra") set (COMPILE_FLAGS "${COMPILE_FLAGS} -Wconversion-extra")
set (COMPILE_FLAGS "${COMPILE_FLAGS} -Wimplicit-procedure") set (COMPILE_FLAGS "${COMPILE_FLAGS} -Wimplicit-procedure")
set (COMPILE_FLAGS "${COMPILE_FLAGS} -Wno-unused-parameter") set (COMPILE_FLAGS "${COMPILE_FLAGS} -Wunused-parameter")
set (COMPILE_FLAGS "${COMPILE_FLAGS} -ffpe-summary=all") set (COMPILE_FLAGS "${COMPILE_FLAGS} -ffpe-summary=all")
# print summary of floating point exeptions (invalid,zero,overflow,underflow,inexact,denormal) # print summary of floating point exeptions (invalid,zero,overflow,underflow,inexact,denormal)
# Additional options # Additional options
# -Warray-temporarieswarnings: because we have many temporary arrays (performance issue?)
# -Wimplicit-interface: no interfaces for lapack/MPI routines # -Wimplicit-interface: no interfaces for lapack/MPI routines
# -Wunsafe-loop-optimizations: warn if the loop cannot be optimized due to nontrivial assumptions # -Wunsafe-loop-optimizations: warn if the loop cannot be optimized due to nontrivial assumptions

View File

@ -27,6 +27,276 @@ lattice_symmetries: Dict[CrystalLattice, CrystalFamily] = {
'cF': 'cubic', 'cF': 'cubic',
} }
orientation_relationships: Dict[str, Dict[CrystalLattice,np.ndarray]] = {
'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),
},
}
class Crystal(): class Crystal():
""" """
@ -200,6 +470,12 @@ class Crystal():
return _immutable[self.family] return _immutable[self.family]
@property
def orientation_relationships(self):
"""Return labels of orientation relationships."""
return [k for k,v in orientation_relationships.items() if self.lattice in v]
@property @property
def standard_triangle(self) -> Union[Dict[str, np.ndarray], None]: def standard_triangle(self) -> Union[Dict[str, np.ndarray], None]:
""" """
@ -727,12 +1003,10 @@ class Crystal():
} }
} }
master = _kinematics[self.lattice][mode] master = _kinematics[self.lattice][mode]
if self.lattice == 'hP': return {'direction':[util.Bravais_to_Miller(uvtw=m[:,0:4]) if self.lattice == 'hP'
return {'direction':[util.Bravais_to_Miller(uvtw=m[:,0:4]) for m in master], else m[:,0:3] for m in master],
'plane': [util.Bravais_to_Miller(hkil=m[:,4:8]) for m in master]} 'plane': [util.Bravais_to_Miller(hkil=m[:,4:8]) if self.lattice == 'hP'
else: else m[:,3:6] for m in master]}
return {'direction':[m[:,0:3] for m in master],
'plane': [m[:,3:6] for m in master]}
def relation_operations(self, def relation_operations(self,
@ -768,280 +1042,10 @@ class Crystal():
https://doi.org/10.1016/j.actamat.2004.11.021 https://doi.org/10.1016/j.actamat.2004.11.021
""" """
_orientation_relationships: Dict[str, Dict[CrystalLattice,np.ndarray]] = { my_relationships = {k:v for k,v in orientation_relationships.items() if self.lattice in v}
'KS': { if model not in my_relationships:
'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),
},
}
orientation_relationships = {k:v for k,v in _orientation_relationships.items() if self.lattice in v}
if model not in orientation_relationships:
raise KeyError(f'unknown orientation relationship "{model}"') raise KeyError(f'unknown orientation relationship "{model}"')
r = orientation_relationships[model] r = my_relationships[model]
sl = self.lattice sl = self.lattice
ol = (set(r)-{sl}).pop() ol = (set(r)-{sl}).pop()

View File

@ -18,7 +18,7 @@ from . import grid_filters
from . import Rotation from . import Rotation
from . import Table from . import Table
from . import Colormap from . import Colormap
from ._typehints import FloatSequence, IntSequence from ._typehints import FloatSequence, IntSequence, IntCollection, NumpyRngSeed
class Grid: class Grid:
""" """
@ -92,10 +92,10 @@ class Grid:
""" """
if not isinstance(other, Grid): if not isinstance(other, Grid):
return NotImplemented return NotImplemented
return bool(np.allclose(other.size,self.size) return bool( np.allclose(other.size,self.size)
and np.allclose(other.origin,self.origin) and np.allclose(other.origin,self.origin)
and np.all(other.cells == self.cells) and np.all(other.cells == self.cells)
and np.all(other.material == self.material)) and np.all(other.material == self.material))
@property @property
@ -191,8 +191,8 @@ class Grid:
ic = {label:v.get(label).reshape(cells,order='F') for label in set(v.labels['Cell Data']) - {'material'}} ic = {label:v.get(label).reshape(cells,order='F') for label in set(v.labels['Cell Data']) - {'material'}}
return Grid(material = v.get('material').reshape(cells,order='F'), return Grid(material = v.get('material').reshape(cells,order='F'),
size = bbox[1] - bbox[0], size = bbox[1] - bbox[0],
origin = bbox[0], origin = bbox[0],
comments = comments, comments = comments,
initial_conditions = ic) initial_conditions = ic)
@ -247,7 +247,7 @@ class Grid:
else: else:
comments.append(line.strip()) comments.append(line.strip())
material = np.empty(int(cells.prod())) # initialize as flat array material = np.empty(cells.prod()) # initialize as flat array
i = 0 i = 0
for line in content[header_length:]: for line in content[header_length:]:
if len(items := line.split('#')[0].split()) == 3: if len(items := line.split('#')[0].split()) == 3:
@ -265,7 +265,7 @@ class Grid:
raise TypeError(f'mismatch between {cells.prod()} expected entries and {i} found') raise TypeError(f'mismatch between {cells.prod()} expected entries and {i} found')
if not np.any(np.mod(material,1) != 0.0): # no float present if not np.any(np.mod(material,1) != 0.0): # no float present
material = material.astype('int') - (1 if material.min() > 0 else 0) material = material.astype(int) - (1 if material.min() > 0 else 0)
return Grid(material.reshape(cells,order='F'),size,origin,comments) return Grid(material.reshape(cells,order='F'),size,origin,comments)
@ -285,6 +285,20 @@ class Grid:
loaded : damask.Grid loaded : damask.Grid
Grid-based geometry from file. Grid-based geometry from file.
Examples
--------
Read a periodic polycrystal generated with Neper.
>>> import damask
>>> N_grains = 20
>>> cells = (32,32,32)
>>> damask.util.run(f'neper -T -n {N_grains} -tesrsize {cells[0]}:{cells[1]}:{cells[2]} -periodicity "all" -format "vtk"')
>>> damask.Grid.load_Neper(f'n{N_grains}-id1.vtk')
cells: 32 × 32 × 32
size: 1.0 × 1.0 × 1.0
origin: 0.0 0.0 0.0 m
# materials: 20
""" """
v = VTK.load(fname,'ImageData') v = VTK.load(fname,'ImageData')
cells = np.array(v.vtk_data.GetDimensions())-1 cells = np.array(v.vtk_data.GetDimensions())-1
@ -913,7 +927,7 @@ class Grid:
cells/self.cells, cells/self.cells,
output=self.material.dtype, output=self.material.dtype,
order=0, order=0,
mode=('wrap' if periodic else 'nearest'), mode='wrap' if periodic else 'nearest',
prefilter=False prefilter=False
), ),
size = self.size, size = self.size,
@ -923,42 +937,64 @@ class Grid:
def clean(self, def clean(self,
stencil: int = 3, distance: float = np.sqrt(3),
selection: IntSequence = None, selection: IntCollection = None,
periodic: bool = True) -> 'Grid': invert_selection: bool = False,
periodic: bool = True,
rng_seed: NumpyRngSeed = None) -> 'Grid':
""" """
Smooth grid by selecting most frequent material index within given stencil at each location. Smooth grid by selecting most frequent material ID within given stencil at each location.
Parameters Parameters
---------- ----------
stencil : int, optional distance : float, optional
Size of smoothing stencil. Voxel distance checked for presence of other materials.
selection : sequence of int, optional Defaults to sqrt(3).
Field values that can be altered. Defaults to all. selection : int or collection of int, optional
Material IDs to consider.
invert_selection : bool, optional
Consider all material IDs except those in selection. Defaults to False.
periodic : bool, optional periodic : bool, optional
Assume grid to be periodic. Defaults to True. Assume grid to be periodic. Defaults to True.
rng_seed : {None, int, array_like[ints], SeedSequence, BitGenerator, Generator}, optional
A seed to initialize the BitGenerator. Defaults to None.
If None, then fresh, unpredictable entropy will be pulled from the OS.
Returns Returns
------- -------
updated : damask.Grid updated : damask.Grid
Updated grid-based geometry. Updated grid-based geometry.
Notes
-----
If multiple material IDs are most frequent within a stencil, a random choice is taken.
""" """
def mostFrequent(arr: np.ndarray, selection = None): def most_frequent(stencil: np.ndarray,
me = arr[arr.size//2] selection: set,
if selection is None or me in selection: rng):
unique, inverse = np.unique(arr, return_inverse=True) me = stencil[stencil.size//2]
return unique[np.argmax(np.bincount(inverse))] if not selection or me in selection:
unique, counts = np.unique(stencil,return_counts=True)
return rng.choice(unique[counts==np.max(counts)])
else: else:
return me return me
return Grid(material = ndimage.filters.generic_filter( rng = np.random.default_rng(rng_seed)
self.material, d = np.floor(distance).astype(int)
mostFrequent, ext = np.linspace(-d,d,1+2*d,dtype=float),
size=(stencil if selection is None else stencil//2*2+1,)*3, xx,yy,zz = np.meshgrid(ext,ext,ext)
mode=('wrap' if periodic else 'nearest'), footprint = xx**2+yy**2+zz**2 <= distance**2+distance*1e-8
extra_keywords=dict(selection=selection), selection_ = set(self.material.flatten()) - set(util.aslist(selection)) if invert_selection else \
).astype(self.material.dtype), set(util.aslist(selection))
material = ndimage.filters.generic_filter(
self.material,
most_frequent,
footprint=footprint,
mode='wrap' if periodic else 'nearest',
extra_keywords=dict(selection=selection_,rng=rng),
).astype(self.material.dtype)
return Grid(material = material,
size = self.size, size = self.size,
origin = self.origin, origin = self.origin,
comments = self.comments+[util.execution_stamp('Grid','clean')], comments = self.comments+[util.execution_stamp('Grid','clean')],
@ -988,14 +1024,15 @@ class Grid:
R: Rotation, R: Rotation,
fill: int = None) -> 'Grid': fill: int = None) -> 'Grid':
""" """
Rotate grid (pad if required). Rotate grid (and pad if required).
Parameters Parameters
---------- ----------
R : damask.Rotation R : damask.Rotation
Rotation to apply to the grid. Rotation to apply to the grid.
fill : int, optional fill : int, optional
Material index to fill the corners. Defaults to material.max() + 1. Material ID to fill enlarged bounding box.
Defaults to material.max() + 1.
Returns Returns
------- -------
@ -1035,9 +1072,11 @@ class Grid:
cells : sequence of int, len (3), optional cells : sequence of int, len (3), optional
Number of cells x,y,z direction. Number of cells x,y,z direction.
offset : sequence of int, len (3), optional offset : sequence of int, len (3), optional
Offset (measured in cells) from old to new grid [0,0,0]. Offset (measured in cells) from old to new grid.
Defaults to [0,0,0].
fill : int, optional fill : int, optional
Material index to fill the background. Defaults to material.max() + 1. Material ID to fill the background.
Defaults to material.max() + 1.
Returns Returns
------- -------
@ -1046,15 +1085,15 @@ class Grid:
Examples Examples
-------- --------
Remove 1/2 of the microstructure in z-direction. Remove lower 1/2 of the microstructure in z-direction.
>>> import numpy as np >>> import numpy as np
>>> import damask >>> import damask
>>> g = damask.Grid(np.zeros([32]*3,int),np.ones(3)*1e-4) >>> g = damask.Grid(np.zeros([32]*3,int),np.ones(3)*1e-4)
>>> g.canvas([32,32,16]) >>> g.canvas([32,32,16],[0,0,16])
cells : 33 x 32 x 16 cells : 33 x 32 x 16
size : 0.0001 x 0.0001 x 5e-05 size : 0.0001 x 0.0001 x 5e-05
origin: 0.0 0.0 0.0 m origin: 0.0 0.0 5e-05 m
# materials: 1 # materials: 1
""" """
@ -1078,16 +1117,16 @@ class Grid:
def substitute(self, def substitute(self,
from_material: IntSequence, from_material: Union[int,IntSequence],
to_material: IntSequence) -> 'Grid': to_material: Union[int,IntSequence]) -> 'Grid':
""" """
Substitute material indices. Substitute material indices.
Parameters Parameters
---------- ----------
from_material : sequence of int from_material : int or sequence of int
Material indices to be substituted. Material indices to be substituted.
to_material : sequence of int to_material : int or sequence of int
New material indices. New material indices.
Returns Returns
@ -1097,7 +1136,8 @@ class Grid:
""" """
material = self.material.copy() material = self.material.copy()
for f,t in zip(from_material,to_material): # ToDo Python 3.10 has strict mode for zip for f,t in zip(from_material if isinstance(from_material,(Sequence,np.ndarray)) else [from_material],
to_material if isinstance(to_material,(Sequence,np.ndarray)) else [to_material]): # ToDo Python 3.10 has strict mode for zip
material[self.material==f] = t material[self.material==f] = t
return Grid(material = material, return Grid(material = material,
@ -1130,28 +1170,31 @@ class Grid:
def vicinity_offset(self, def vicinity_offset(self,
vicinity: int = 1, distance: float = np.sqrt(3),
offset: int = None, offset: int = None,
trigger: IntSequence = [], selection: IntCollection = None,
invert_selection: bool = False,
periodic: bool = True) -> 'Grid': periodic: bool = True) -> 'Grid':
""" """
Offset material index of points in the vicinity of xxx. Offset material ID of points in the vicinity of selected (or just other) material IDs.
Different from themselves (or listed as triggers) within a given (cubic) vicinity, Trigger points are variations in material ID, i.e. grain/phase
i.e. within the region close to a grain/phase boundary. boundaries or explicitly given material IDs.
ToDo: use include/exclude as in seeds.from_grid
Parameters Parameters
---------- ----------
vicinity : int, optional distance : float, optional
Voxel distance checked for presence of other materials. Voxel distance checked for presence of other materials.
Defaults to 1. Defaults to sqrt(3).
offset : int, optional offset : int, optional
Offset (positive or negative) to tag material indices, Offset (positive or negative) to tag material IDs.
defaults to material.max()+1. Defaults to material.max()+1.
trigger : sequence of int, optional selection : int or collection of int, optional
List of material indices that trigger a change. Material IDs that trigger an offset.
Defaults to [], meaning that any different neighbor triggers a change. Defaults to any other than own material ID.
invert_selection : bool, optional
Consider all material IDs except those in selection.
Defaults to False.
periodic : bool, optional periodic : bool, optional
Assume grid to be periodic. Defaults to True. Assume grid to be periodic. Defaults to True.
@ -1161,17 +1204,24 @@ class Grid:
Updated grid-based geometry. Updated grid-based geometry.
""" """
def tainted_neighborhood(stencil: np.ndarray, trigger): def tainted_neighborhood(stencil: np.ndarray, selection: set):
me = stencil[stencil.shape[0]//2] me = stencil[stencil.size//2]
return np.any(stencil != me if len(trigger) == 0 else return np.any(stencil != me if not selection else
np.in1d(stencil,np.array(list(set(trigger) - {me})))) np.in1d(stencil,np.array(list(selection - {me}))))
d = np.floor(distance).astype(int)
ext = np.linspace(-d,d,1+2*d,dtype=float),
xx,yy,zz = np.meshgrid(ext,ext,ext)
footprint = xx**2+yy**2+zz**2 <= distance**2+distance*1e-8
offset_ = np.nanmax(self.material)+1 if offset is None else offset offset_ = np.nanmax(self.material)+1 if offset is None else offset
selection_ = set(self.material.flatten()) - set(util.aslist(selection)) if invert_selection else \
set(util.aslist(selection))
mask = ndimage.filters.generic_filter(self.material, mask = ndimage.filters.generic_filter(self.material,
tainted_neighborhood, tainted_neighborhood,
size=1+2*vicinity, footprint=footprint,
mode='wrap' if periodic else 'nearest', mode='wrap' if periodic else 'nearest',
extra_keywords={'trigger':trigger}) extra_keywords=dict(selection=selection_),
)
return Grid(material = np.where(mask, self.material + offset_,self.material), return Grid(material = np.where(mask, self.material + offset_,self.material),
size = self.size, size = self.size,

View File

@ -824,7 +824,7 @@ class Orientation(Rotation,Crystal):
Parameters Parameters
---------- ----------
N_slip|N_twin : '*' or iterable of int N_slip|N_twin : '*' or sequence of int
Number of deformation systems per family of the deformation system. Number of deformation systems per family of the deformation system.
Use '*' to select all. Use '*' to select all.
@ -870,10 +870,36 @@ class Orientation(Rotation,Crystal):
def related(self: MyType, def related(self: MyType,
model: str) -> MyType: model: str) -> MyType:
""" """
Orientations derived from the given relationship. All orientations related to self by given relationship model.
One dimension (length according to number of related orientations) Parameters
is added to the left of the Rotation array. ----------
model : str
Orientation relationship model selected from self.orientation_relationships.
Returns
-------
Orientations related to self following the selected
model for the orientation relationship.
Examples
--------
Face-centered cubic orientations following from a
body-centered cubic crystal in "Cube" orientation according
to the Bain orientation relationship (cI -> cF).
>>> import numpy as np
>>> import damask
>>> np.set_printoptions(3,suppress=True,floatmode='fixed')
>>> damask.Orientation(lattice='cI').related('Bain')
Crystal family: cubic
Bravais lattice: cF
a=1 m, b=1 m, c=1 m
α=90°, β=90°, γ=90°
Quaternions of shape (3,)
[[0.924 0.383 0.000 0.000]
[0.924 0.000 0.383 0.000]
[0.924 0.000 0.000 0.383]]
""" """
lattice,o = self.relation_operations(model) lattice,o = self.relation_operations(model)

View File

@ -4,7 +4,6 @@ import fnmatch
import os import os
import copy import copy
import datetime import datetime
import warnings
import xml.etree.ElementTree as ET # noqa import xml.etree.ElementTree as ET # noqa
import xml.dom.minidom import xml.dom.minidom
from pathlib import Path from pathlib import Path
@ -28,21 +27,6 @@ h5py3 = h5py.__version__[0] == '3'
chunk_size = 1024**2//8 # for compression in HDF5 chunk_size = 1024**2//8 # for compression in HDF5
def _view_transition(what,datasets,increments,times,phases,homogenizations,fields):
if (datasets is not None and what is None) or (what is not None and datasets is None):
raise ValueError('"what" and "datasets" need to be used as a pair')
if datasets is not None or what is not None:
warnings.warn('arguments "what" and "datasets" will be removed in DAMASK v3.0.0-alpha7', DeprecationWarning,2)
return what,datasets
if sum(1 for _ in filter(None.__ne__, [increments,times,phases,homogenizations,fields])) > 1:
raise ValueError('only one out of "increments", "times", "phases", "homogenizations", and "fields" can be used')
else:
if increments is not None: return "increments", increments
if times is not None: return "times", times
if phases is not None: return "phases", phases
if homogenizations is not None: return "homogenizations", homogenizations
if fields is not None: return "fields", fields
def _read(dataset): def _read(dataset):
"""Read a dataset and its metadata into a numpy.ndarray.""" """Read a dataset and its metadata into a numpy.ndarray."""
metadata = {k:(v.decode() if not h5py3 and type(v) is bytes else v) for k,v in dataset.attrs.items()} metadata = {k:(v.decode() if not h5py3 and type(v) is bytes else v) for k,v in dataset.attrs.items()}
@ -185,7 +169,13 @@ class Result:
return util.srepr([util.deemph(header)] + first + in_between + last) return util.srepr([util.deemph(header)] + first + in_between + last)
def _manage_view(self,action,what,datasets): def _manage_view(self,
action,
increments=None,
times=None,
phases=None,
homogenizations=None,
fields=None):
""" """
Manages the visibility of the groups. Manages the visibility of the groups.
@ -193,11 +183,6 @@ class Result:
---------- ----------
action : str action : str
Select from 'set', 'add', and 'del'. Select from 'set', 'add', and 'del'.
what : str
Attribute to change (must be from self.visible).
datasets : (list of) int (for increments), (list of) float (for times), (list of) str, or bool
Name of datasets; supports '?' and '*' wildcards.
True is equivalent to '*', False is equivalent to [].
Returns Returns
------- -------
@ -205,47 +190,52 @@ class Result:
Modified or new view on the DADF5 file. Modified or new view on the DADF5 file.
""" """
# allow True/False and string arguments if increments is not None and times is not None:
if datasets is True: raise ValueError('"increments" and "times" are mutually exclusive')
datasets = '*'
elif datasets is False or datasets is None:
datasets = []
choice = list(datasets).copy() if hasattr(datasets,'__iter__') and not isinstance(datasets,str) else \
[datasets]
what_ = what if what.endswith('s') else what+'s'
if what_ == 'increments':
choice = [c if isinstance(c,str) and c.startswith('increment_') else
self.increments[c] if isinstance(c,int) and c<0 else
f'increment_{c}' for c in choice]
elif what_ == 'times':
what_ = 'increments'
if choice == ['*']:
choice = self.increments
else:
iterator = map(float,choice)
choice = []
for c in iterator:
idx = np.searchsorted(self.times,c)
if idx >= len(self.times): continue
if np.isclose(c,self.times[idx]):
choice.append(self.increments[idx])
elif np.isclose(c,self.times[idx+1]):
choice.append(self.increments[idx+1])
valid = _match(choice,getattr(self,what_))
existing = set(self.visible[what_])
dup = self.copy() dup = self.copy()
if action == 'set': for what,datasets in zip(['increments','times','phases','homogenizations','fields'],
dup.visible[what_] = sorted(set(valid), key=util.natural_sort) [ increments, times, phases, homogenizations, fields ]):
elif action == 'add': if datasets is None:
add = existing.union(valid) continue
dup.visible[what_] = sorted(add, key=util.natural_sort) # allow True/False and string arguments
elif action == 'del': elif datasets is True:
diff = existing.difference(valid) datasets = '*'
dup.visible[what_] = sorted(diff, key=util.natural_sort) elif datasets is False:
datasets = []
choice = list(datasets).copy() if hasattr(datasets,'__iter__') and not isinstance(datasets,str) else \
[datasets]
if what == 'increments':
choice = [c if isinstance(c,str) and c.startswith('increment_') else
self.increments[c] if isinstance(c,int) and c<0 else
f'increment_{c}' for c in choice]
elif what == 'times':
what = 'increments'
if choice == ['*']:
choice = self.increments
else:
iterator = map(float,choice)
choice = []
for c in iterator:
idx = np.searchsorted(self.times,c)
if idx >= len(self.times): continue
if np.isclose(c,self.times[idx]):
choice.append(self.increments[idx])
elif np.isclose(c,self.times[idx+1]):
choice.append(self.increments[idx+1])
valid = _match(choice,getattr(self,what))
existing = set(self.visible[what])
if action == 'set':
dup.visible[what] = sorted(set(valid), key=util.natural_sort)
elif action == 'add':
add = existing.union(valid)
dup.visible[what] = sorted(add, key=util.natural_sort)
elif action == 'del':
diff = existing.difference(valid)
dup.visible[what] = sorted(diff, key=util.natural_sort)
return dup return dup
@ -298,13 +288,13 @@ class Result:
return selected return selected
def view(self,what=None,datasets=None,*, def view(self,*,
increments=None, increments=None,
times=None, times=None,
phases=None, phases=None,
homogenizations=None, homogenizations=None,
fields=None, fields=None,
protected=None): protected=None):
""" """
Set view. Set view.
@ -313,11 +303,6 @@ class Result:
Parameters Parameters
---------- ----------
what : {'increments', 'times', 'phases', 'homogenizations', 'fields'}
Attribute to change. DEPRECATED.
datasets : (list of) int (for increments), (list of) float (for times), (list of) str, or bool
Name of datasets; supports '?' and '*' wildcards. DEPRECATED.
True is equivalent to '*', False is equivalent to [].
increments: (list of) int, (list of) str, or bool, optional. increments: (list of) int, (list of) str, or bool, optional.
Number(s) of increments to select. Number(s) of increments to select.
times: (list of) float, (list of) str, or bool, optional. times: (list of) float, (list of) str, or bool, optional.
@ -351,24 +336,16 @@ class Result:
>>> r_t10to40 = r.view(times=r.times_in_range(10.0,40.0)) >>> r_t10to40 = r.view(times=r.times_in_range(10.0,40.0))
""" """
v = _view_transition(what,datasets,increments,times,phases,homogenizations,fields) dup = self._manage_view('set',increments,times,phases,homogenizations,fields)
if protected is not None: if protected is not None:
if v is None:
dup = self.copy()
else:
what_,datasets_ = v
dup = self._manage_view('set',what_,datasets_)
if not protected: if not protected:
print(util.warn('Warning: Modification of existing datasets allowed!')) print(util.warn('Warning: Modification of existing datasets allowed!'))
dup._protected = protected dup._protected = protected
else:
what_,datasets_ = v
dup = self._manage_view('set',what_,datasets_)
return dup return dup
def view_more(self,what=None,datasets=None,*, def view_more(self,*,
increments=None, increments=None,
times=None, times=None,
phases=None, phases=None,
@ -382,11 +359,6 @@ class Result:
Parameters Parameters
---------- ----------
what : {'increments', 'times', 'phases', 'homogenizations', 'fields'}
Attribute to change. DEPRECATED.
datasets : (list of) int (for increments), (list of) float (for times), (list of) str, or bool
Name of datasets; supports '?' and '*' wildcards. DEPRECATED.
True is equivalent to '*', False is equivalent to [].
increments: (list of) int, (list of) str, or bool, optional. increments: (list of) int, (list of) str, or bool, optional.
Number(s) of increments to select. Number(s) of increments to select.
times: (list of) float, (list of) str, or bool, optional. times: (list of) float, (list of) str, or bool, optional.
@ -413,11 +385,10 @@ class Result:
>>> r_first_and_last = r.first.view_more(increments=-1) >>> r_first_and_last = r.first.view_more(increments=-1)
""" """
what_, datasets_ = _view_transition(what,datasets,increments,times,phases,homogenizations,fields) return self._manage_view('add',increments,times,phases,homogenizations,fields)
return self._manage_view('add',what_,datasets_)
def view_less(self,what=None,datasets=None,*, def view_less(self,*,
increments=None, increments=None,
times=None, times=None,
phases=None, phases=None,
@ -431,11 +402,6 @@ class Result:
Parameters Parameters
---------- ----------
what : {'increments', 'times', 'phases', 'homogenizations', 'fields'}
Attribute to change. DEPRECATED.
datasets : (list of) int (for increments), (list of) float (for times), (list of) str, or bool
Name of datasets; supports '?' and '*' wildcards. DEPRECATED.
True is equivalent to '*', False is equivalent to [].
increments: (list of) int, (list of) str, or bool, optional. increments: (list of) int, (list of) str, or bool, optional.
Number(s) of increments to select. Number(s) of increments to select.
times: (list of) float, (list of) str, or bool, optional. times: (list of) float, (list of) str, or bool, optional.
@ -461,8 +427,7 @@ class Result:
>>> r_deformed = r_all.view_less(increments=0) >>> r_deformed = r_all.view_less(increments=0)
""" """
what_, datasets_ = _view_transition(what,datasets,increments,times,phases,homogenizations,fields) return self._manage_view('del',increments,times,phases,homogenizations,fields)
return self._manage_view('del',what_,datasets_)
def rename(self,name_src,name_dst): def rename(self,name_src,name_dst):
@ -1839,9 +1804,9 @@ class Result:
d = obj.attrs['description'] if h5py3 else obj.attrs['description'].decode() d = obj.attrs['description'] if h5py3 else obj.attrs['description'].decode()
if not Path(name).exists() or overwrite: if not Path(name).exists() or overwrite:
with open(name,'w') as f_out: f_out.write(obj[0].decode()) with open(name,'w') as f_out: f_out.write(obj[0].decode())
print(f"Exported {d} to '{name}'.") print(f'Exported {d} to "{name}".')
else: else:
print(f"'{name}' exists, {d} not exported.") print(f'"{name}" exists, {d} not exported.')
elif type(obj) == h5py.Group: elif type(obj) == h5py.Group:
os.makedirs(name, exist_ok=True) os.makedirs(name, exist_ok=True)

View File

@ -1,6 +1,6 @@
"""Functionality for typehints.""" """Functionality for typehints."""
from typing import Sequence, Union, Literal, TextIO from typing import Sequence, Union, Literal, TextIO, Collection
from pathlib import Path from pathlib import Path
import numpy as np import numpy as np
@ -8,6 +8,7 @@ import numpy as np
FloatSequence = Union[np.ndarray,Sequence[float]] FloatSequence = Union[np.ndarray,Sequence[float]]
IntSequence = Union[np.ndarray,Sequence[int]] IntSequence = Union[np.ndarray,Sequence[int]]
IntCollection = Union[np.ndarray,Collection[int]]
FileHandle = Union[TextIO, str, Path] FileHandle = Union[TextIO, str, Path]
CrystalFamily = Union[None,Literal['triclinic', 'monoclinic', 'orthorhombic', 'tetragonal', 'hexagonal', 'cubic']] CrystalFamily = Union[None,Literal['triclinic', 'monoclinic', 'orthorhombic', 'tetragonal', 'hexagonal', 'cubic']]
CrystalLattice = Union[None,Literal['aP', 'mP', 'mS', 'oP', 'oS', 'oI', 'oF', 'tP', 'tI', 'hP', 'cP', 'cI', 'cF']] CrystalLattice = Union[None,Literal['aP', 'mP', 'mS', 'oP', 'oS', 'oI', 'oF', 'tP', 'tI', 'hP', 'cP', 'cI', 'cF']]

View File

@ -6,7 +6,8 @@ from typing import Tuple as _Tuple
from scipy import spatial as _spatial from scipy import spatial as _spatial
import numpy as _np import numpy as _np
from ._typehints import FloatSequence as _FloatSequence, IntSequence as _IntSequence, NumpyRngSeed as _NumpyRngSeed from ._typehints import FloatSequence as _FloatSequence, IntSequence as _IntSequence, \
NumpyRngSeed as _NumpyRngSeed, IntCollection as _IntCollection
from . import util as _util from . import util as _util
from . import grid_filters as _grid_filters from . import grid_filters as _grid_filters
@ -106,7 +107,7 @@ def from_Poisson_disc(size: _FloatSequence,
def from_grid(grid, def from_grid(grid,
selection: _IntSequence = None, selection: _IntCollection = None,
invert_selection: bool = False, invert_selection: bool = False,
average: bool = False, average: bool = False,
periodic: bool = True) -> _Tuple[_np.ndarray, _np.ndarray]: periodic: bool = True) -> _Tuple[_np.ndarray, _np.ndarray]:
@ -117,7 +118,7 @@ def from_grid(grid,
---------- ----------
grid : damask.Grid grid : damask.Grid
Grid from which the material IDs are used as seeds. Grid from which the material IDs are used as seeds.
selection : sequence of int, optional selection : int or collection of int, optional
Material IDs to consider. Material IDs to consider.
invert_selection : bool, optional invert_selection : bool, optional
Consider all material IDs except those in selection. Defaults to False. Consider all material IDs except those in selection. Defaults to False.
@ -134,7 +135,7 @@ def from_grid(grid,
""" """
material = grid.material.reshape((-1,1),order='F') material = grid.material.reshape((-1,1),order='F')
mask = _np.full(grid.cells.prod(),True,dtype=bool) if selection is None else \ mask = _np.full(grid.cells.prod(),True,dtype=bool) if selection is None else \
_np.isin(material,selection,invert=invert_selection).flatten() _np.isin(material,_util.aslist(selection),invert=invert_selection).flatten()
coords = _grid_filters.coordinates0_point(grid.cells,grid.size).reshape(-1,3,order='F') coords = _grid_filters.coordinates0_point(grid.cells,grid.size).reshape(-1,3,order='F')
if not average: if not average:

View File

@ -6,17 +6,18 @@ import os
import subprocess import subprocess
import shlex import shlex
import re import re
import signal
import fractions import fractions
from collections import abc from collections import abc
from functools import reduce from functools import reduce, partial
from typing import Callable, Union, Iterable, Sequence, Dict, List, Tuple, Literal, Any from typing import Callable, Union, Iterable, Sequence, Dict, List, Tuple, Literal, Any, Collection
from pathlib import Path from pathlib import Path
import numpy as np import numpy as np
import h5py import h5py
from . import version from . import version
from ._typehints import FloatSequence, NumpyRngSeed from ._typehints import FloatSequence, NumpyRngSeed, IntCollection
# limit visibility # limit visibility
__all__=[ __all__=[
@ -174,21 +175,35 @@ def run(cmd: str,
Output of the executed command. Output of the executed command.
""" """
def pass_signal(sig,_,proc,default):
proc.send_signal(sig)
signal.signal(sig,default)
signal.raise_signal(sig)
signals = [signal.SIGINT,signal.SIGTERM]
print(f"running '{cmd}' in '{wd}'") print(f"running '{cmd}' in '{wd}'")
process = subprocess.run(shlex.split(cmd), process = subprocess.Popen(shlex.split(cmd),
stdout = subprocess.PIPE, stdout = subprocess.PIPE,
stderr = subprocess.PIPE, stderr = subprocess.PIPE,
env = os.environ if env is None else env, env = os.environ if env is None else env,
cwd = wd, cwd = wd,
encoding = 'utf-8', encoding = 'utf-8')
timeout = timeout) # ensure that process is terminated (https://stackoverflow.com/questions/22916783)
sig_states = [signal.signal(sig,partial(pass_signal,proc=process,default=signal.getsignal(sig))) for sig in signals]
try:
stdout,stderr = process.communicate(timeout=timeout)
finally:
for sig,state in zip(signals,sig_states):
signal.signal(sig,state)
if process.returncode != 0: if process.returncode != 0:
print(process.stdout) print(stdout)
print(process.stderr) print(stderr)
raise RuntimeError(f"'{cmd}' failed with returncode {process.returncode}") raise RuntimeError(f"'{cmd}' failed with returncode {process.returncode}")
return process.stdout, process.stderr return stdout, stderr
execute = run execute = run
@ -722,7 +737,6 @@ def dict_flatten(d: Dict) -> Dict:
return new return new
def tail_repack(extended: Union[str, Sequence[str]], def tail_repack(extended: Union[str, Sequence[str]],
existing: List[str] = []) -> List[str]: existing: List[str] = []) -> List[str]:
""" """
@ -753,6 +767,24 @@ def tail_repack(extended: Union[str, Sequence[str]],
list(extended[len(existing):])) list(extended[len(existing):]))
def aslist(arg: Union[IntCollection,int,None]) -> List:
"""
Transform argument to list.
Parameters
----------
arg : int or collection of int or None
Entity to transform into list.
Returns
-------
transformed : list
Entity transformed into list.
"""
return [] if arg is None else list(arg) if isinstance(arg,(np.ndarray,Collection)) else [arg]
#################################################################################################### ####################################################################################################
# Classes # Classes
#################################################################################################### ####################################################################################################

View File

@ -3,7 +3,7 @@
<ImageData WholeExtent="0 8 0 5 0 4" Origin="0 0 0" Spacing="0.000001 0.0000010000000000000002 0.000001" Direction="1 0 0 0 1 0 0 0 1"> <ImageData WholeExtent="0 8 0 5 0 4" Origin="0 0 0" Spacing="0.000001 0.0000010000000000000002 0.000001" Direction="1 0 0 0 1 0 0 0 1">
<FieldData> <FieldData>
<Array type="String" Name="comments" NumberOfTuples="1" format="binary"> <Array type="String" Name="comments" NumberOfTuples="1" format="binary">
AQAAAACAAAA+AAAAQQAAAA==eF5LScxNLM7Wc0/Nz9VLzklNzFMos7TUAyNdSyDQLagsSS0uUdAwMjC01DU01DUwUjA0tDK1sDIw0GQAAFT8EKY= AQAAAACAAAA+AAAAQQAAAA==eF5LScxNLM7Wcy/KTNFLzklNzFMos7TUAyNdSyDQLagsSS0uUdAwMjC01DU01DUwUjA0tDK1sDIw0GQAAFSoEKQ=
</Array> </Array>
</FieldData> </FieldData>
<Piece Extent="0 8 0 5 0 4"> <Piece Extent="0 8 0 5 0 4">

View File

@ -3,7 +3,7 @@
<ImageData WholeExtent="0 8 0 5 0 4" Origin="0 0 0" Spacing="0.000001 0.0000010000000000000002 0.000001" Direction="1 0 0 0 1 0 0 0 1"> <ImageData WholeExtent="0 8 0 5 0 4" Origin="0 0 0" Spacing="0.000001 0.0000010000000000000002 0.000001" Direction="1 0 0 0 1 0 0 0 1">
<FieldData> <FieldData>
<Array type="String" Name="comments" NumberOfTuples="1" format="binary"> <Array type="String" Name="comments" NumberOfTuples="1" format="binary">
AQAAAACAAAA+AAAAQQAAAA==eF5LScxNLM7Wc0/Nz9VLzklNzFMos7TUAyNdSyDQLagsSS0uUdAwMjC01DU01DUwUjA0tDK1sDIw0GQAAFT8EKY= AQAAAACAAAA+AAAAQQAAAA==eF5LScxNLM7Wcy/KTNFLzklNzFMos7TUAyNdSyDQLagsSS0uUdAwMjC01DU01DUwUjA0tDK1sDIw0GQAAFSoEKQ=
</Array> </Array>
</FieldData> </FieldData>
<Piece Extent="0 8 0 5 0 4"> <Piece Extent="0 8 0 5 0 4">

View File

@ -3,7 +3,7 @@
<ImageData WholeExtent="0 8 0 5 0 4" Origin="0 0 0" Spacing="0.000001 0.0000010000000000000002 0.000001" Direction="1 0 0 0 1 0 0 0 1"> <ImageData WholeExtent="0 8 0 5 0 4" Origin="0 0 0" Spacing="0.000001 0.0000010000000000000002 0.000001" Direction="1 0 0 0 1 0 0 0 1">
<FieldData> <FieldData>
<Array type="String" Name="comments" NumberOfTuples="1" format="binary"> <Array type="String" Name="comments" NumberOfTuples="1" format="binary">
AQAAAACAAAA+AAAAQQAAAA==eF5LScxNLM7Wc0/Nz9VLzklNzFMos7TUAyNdSyDQLagsSS0uUdAwMjC01DU01DUwUjA0tDK1sDIw0GQAAFT8EKY= AQAAAACAAAA+AAAAQQAAAA==eF5LScxNLM7Wcy/KTNFLzklNzFMos7TUAyNdSyDQLagsSS0uUdAwMjC01DU01DUwUjA0tDK1sDIw0GQAAFSoEKQ=
</Array> </Array>
</FieldData> </FieldData>
<Piece Extent="0 8 0 5 0 4"> <Piece Extent="0 8 0 5 0 4">

View File

@ -3,7 +3,7 @@
<ImageData WholeExtent="0 8 0 5 0 4" Origin="0 0 0" Spacing="0.000001 0.0000010000000000000002 0.000001" Direction="1 0 0 0 1 0 0 0 1"> <ImageData WholeExtent="0 8 0 5 0 4" Origin="0 0 0" Spacing="0.000001 0.0000010000000000000002 0.000001" Direction="1 0 0 0 1 0 0 0 1">
<FieldData> <FieldData>
<Array type="String" Name="comments" NumberOfTuples="1" format="binary"> <Array type="String" Name="comments" NumberOfTuples="1" format="binary">
AQAAAACAAAA+AAAAQQAAAA==eF5LScxNLM7Wc0/Nz9VLzklNzFMos7TUAyNdSyDQLagsSS0uUdAwMjC01DU01DUwUjA0tDK1sDIw0GQAAFT8EKY= AQAAAACAAAA+AAAAQQAAAA==eF5LScxNLM7Wcy/KTNFLzklNzFMos7TUAyNdSyDQLagsSS0uUdAwMjC01DU01DUwUjA0tDK1sDIw0GQAAFSoEKQ=
</Array> </Array>
</FieldData> </FieldData>
<Piece Extent="0 8 0 5 0 4"> <Piece Extent="0 8 0 5 0 4">

View File

@ -3,7 +3,7 @@
<ImageData WholeExtent="0 8 0 5 0 4" Origin="0 0 0" Spacing="0.000001 0.0000010000000000000002 0.000001" Direction="1 0 0 0 1 0 0 0 1"> <ImageData WholeExtent="0 8 0 5 0 4" Origin="0 0 0" Spacing="0.000001 0.0000010000000000000002 0.000001" Direction="1 0 0 0 1 0 0 0 1">
<FieldData> <FieldData>
<Array type="String" Name="comments" NumberOfTuples="1" format="binary"> <Array type="String" Name="comments" NumberOfTuples="1" format="binary">
AQAAAACAAAA+AAAAQQAAAA==eF5LScxNLM7Wc0/Nz9VLzklNzFMos7TUAyNdSyDQLagsSS0uUdAwMjC01DU01DUwUjA0tDK1sDIw0GQAAFT8EKY= AQAAAACAAAA+AAAAQQAAAA==eF5LScxNLM7Wcy/KTNFLzklNzFMos7TUAyNdSyDQLagsSS0uUdAwMjC01DU01DUwUjA0tDK1sDIw0GQAAFSoEKQ=
</Array> </Array>
</FieldData> </FieldData>
<Piece Extent="0 8 0 5 0 4"> <Piece Extent="0 8 0 5 0 4">
@ -11,7 +11,7 @@
</PointData> </PointData>
<CellData> <CellData>
<DataArray type="Int64" Name="material" format="binary" RangeMin="1" RangeMax="41"> <DataArray type="Int64" Name="material" format="binary" RangeMin="1" RangeMax="41">
AQAAAACAAAAABQAAagAAAA==eF7t0rkOglAARFExLrgCKuKuqLj8/w9acCoSY7B+05x+cqNOvSj4l92GPfY54JAxRxxzwilnnDNhyowLLrlizjULbrjljnseeOSJZ15Y8sob76z44JMvvtn8L9jObz2GDuv96vADk5QHBg== AQAAAACAAAAABQAAhAAAAA==eF7t0jcOAjEURVGGnHOOQ4b9b5CC8xtLNAwlbk5hPUuWblZ6n+zvV5ZZYZU11tlgky22E+PdPnsccsARx+ww9jPOuWDOFddM/3Pljfvk/sgTz7ww3d/54JPlv4X8VYexj466jP6ix+gvekw7nHDKTx0umXa44ZY7Rn8H5iza4QtoVQaf
</DataArray> </DataArray>
</CellData> </CellData>
</Piece> </Piece>

View File

@ -0,0 +1,19 @@
<?xml version="1.0"?>
<VTKFile type="ImageData" version="0.1" byte_order="LittleEndian" header_type="UInt32" compressor="vtkZLibDataCompressor">
<ImageData WholeExtent="0 8 0 5 0 4" Origin="0 0 0" Spacing="0.000001 0.0000010000000000000002 0.000001" Direction="1 0 0 0 1 0 0 0 1">
<FieldData>
<Array type="String" Name="comments" NumberOfTuples="1" format="binary">
AQAAAACAAAA+AAAAQQAAAA==eF5LScxNLM7Wcy/KTNFLzklNzFMos7TUAyNdSyDQLagsSS0uUdAwMjC01DU01DUwUjA0tDK1sDIw0GQAAFSoEKQ=
</Array>
</FieldData>
<Piece Extent="0 8 0 5 0 4">
<PointData>
</PointData>
<CellData>
<DataArray type="Int64" Name="material" format="binary" RangeMin="1" RangeMax="40">
AQAAAACAAAAABQAAkAAAAA==eF7t070OgkAQRWExKo0GDREMaNjCv/d/QgvPbU5CQw3Nl5nZZZPlUm3+T7W6yK3c4Un9rK/V9/youlN9wzO2ml/xobrHghfM+Xcc0edPWDTP/ie+5AHf+MEv+h5Wl+nvsVff+ZvLcfKUHHtdctegc9RK5zL7Cmb/IJPf5DLvT36Sx7n/MHnMPTh/8QfFJwU8
</DataArray>
</CellData>
</Piece>
</ImageData>
</VTKFile>

View File

@ -3,7 +3,7 @@
<ImageData WholeExtent="0 8 0 5 0 4" Origin="0 0 0" Spacing="0.000001 0.0000010000000000000002 0.000001" Direction="1 0 0 0 1 0 0 0 1"> <ImageData WholeExtent="0 8 0 5 0 4" Origin="0 0 0" Spacing="0.000001 0.0000010000000000000002 0.000001" Direction="1 0 0 0 1 0 0 0 1">
<FieldData> <FieldData>
<Array type="String" Name="comments" NumberOfTuples="1" format="binary"> <Array type="String" Name="comments" NumberOfTuples="1" format="binary">
AQAAAACAAAA+AAAAQQAAAA==eF5LScxNLM7Wc0/Nz9VLzklNzFMos7TUAyNdSyDQLagsSS0uUdAwMjC01DU01DUwUjA0tDK1sDIw0GQAAFT8EKY= AQAAAACAAAA+AAAAQQAAAA==eF5LScxNLM7Wcy/KTNFLzklNzFMos7TUAyNdSyDQLagsSS0uUdAwMjC01DU01DUwUjA0tDK1sDIw0GQAAFSoEKQ=
</Array> </Array>
</FieldData> </FieldData>
<Piece Extent="0 8 0 5 0 4"> <Piece Extent="0 8 0 5 0 4">

View File

@ -0,0 +1,19 @@
<?xml version="1.0"?>
<VTKFile type="ImageData" version="0.1" byte_order="LittleEndian" header_type="UInt32" compressor="vtkZLibDataCompressor">
<ImageData WholeExtent="0 8 0 5 0 4" Origin="0 0 0" Spacing="0.000001 0.0000010000000000000002 0.000001" Direction="1 0 0 0 1 0 0 0 1">
<FieldData>
<Array type="String" Name="comments" NumberOfTuples="1" format="binary">
AQAAAACAAAA+AAAAQQAAAA==eF5LScxNLM7Wcy/KTNFLzklNzFMos7TUAyNdSyDQLagsSS0uUdAwMjC01DU01DUwUjA0tDK1sDIw0GQAAFSoEKQ=
</Array>
</FieldData>
<Piece Extent="0 8 0 5 0 4">
<PointData>
</PointData>
<CellData>
<DataArray type="Int64" Name="material" format="binary" RangeMin="1" RangeMax="41">
AQAAAACAAAAABQAAZwAAAA==eF7t0rcOgmAAhVEgNmyo2AuoWN//BR04EwsJcfzvcvabL47qxcFOJg177HPAIUdMOeaEU844Z8YFl1wx55obbrnjngceeeKZFxYseeWNd1Z88MkX3/zwy+Z/wf8YOqzX1uEPlgwHCA==
</DataArray>
</CellData>
</Piece>
</ImageData>
</VTKFile>

View File

@ -3,7 +3,7 @@
<ImageData WholeExtent="0 8 0 5 0 4" Origin="0 0 0" Spacing="0.000001 0.0000010000000000000002 0.000001" Direction="1 0 0 0 1 0 0 0 1"> <ImageData WholeExtent="0 8 0 5 0 4" Origin="0 0 0" Spacing="0.000001 0.0000010000000000000002 0.000001" Direction="1 0 0 0 1 0 0 0 1">
<FieldData> <FieldData>
<Array type="String" Name="comments" NumberOfTuples="1" format="binary"> <Array type="String" Name="comments" NumberOfTuples="1" format="binary">
AQAAAACAAAA+AAAAQQAAAA==eF5LScxNLM7Wc0/Nz9VLzklNzFMos7TUAyNdSyDQLagsSS0uUdAwMjC01DU01DUwUjA0tDK1sDIw0GQAAFT8EKY= AQAAAACAAAA+AAAAQQAAAA==eF5LScxNLM7Wcy/KTNFLzklNzFMos7TUAyNdSyDQLagsSS0uUdAwMjC01DU01DUwUjA0tDK1sDIw0GQAAFSoEKQ=
</Array> </Array>
</FieldData> </FieldData>
<Piece Extent="0 8 0 5 0 4"> <Piece Extent="0 8 0 5 0 4">

View File

@ -3,7 +3,7 @@
<ImageData WholeExtent="0 8 0 5 0 4" Origin="0 0 0" Spacing="0.000001 0.0000010000000000000002 0.000001" Direction="1 0 0 0 1 0 0 0 1"> <ImageData WholeExtent="0 8 0 5 0 4" Origin="0 0 0" Spacing="0.000001 0.0000010000000000000002 0.000001" Direction="1 0 0 0 1 0 0 0 1">
<FieldData> <FieldData>
<Array type="String" Name="comments" NumberOfTuples="1" format="binary"> <Array type="String" Name="comments" NumberOfTuples="1" format="binary">
AQAAAACAAAA+AAAAQQAAAA==eF5LScxNLM7Wc0/Nz9VLzklNzFMos7TUAyNdSyDQLagsSS0uUdAwMjC01DU01DUwUjA0tDK1sDIw0GQAAFT8EKY= AQAAAACAAAA+AAAAQQAAAA==eF5LScxNLM7Wcy/KTNFLzklNzFMos7TUAyNdSyDQLagsSS0uUdAwMjC01DU01DUwUjA0tDK1sDIw0GQAAFSoEKQ=
</Array> </Array>
</FieldData> </FieldData>
<Piece Extent="0 8 0 5 0 4"> <Piece Extent="0 8 0 5 0 4">

View File

@ -3,7 +3,7 @@
<ImageData WholeExtent="0 8 0 5 0 4" Origin="0 0 0" Spacing="0.000001 0.0000010000000000000002 0.000001" Direction="1 0 0 0 1 0 0 0 1"> <ImageData WholeExtent="0 8 0 5 0 4" Origin="0 0 0" Spacing="0.000001 0.0000010000000000000002 0.000001" Direction="1 0 0 0 1 0 0 0 1">
<FieldData> <FieldData>
<Array type="String" Name="comments" NumberOfTuples="1" format="binary"> <Array type="String" Name="comments" NumberOfTuples="1" format="binary">
AQAAAACAAAA+AAAAQQAAAA==eF5LScxNLM7Wc0/Nz9VLzklNzFMos7TUAyNdSyDQLagsSS0uUdAwMjC01DU01DUwUjA0tDK1sDIw0GQAAFT8EKY= AQAAAACAAAA+AAAAQQAAAA==eF5LScxNLM7Wcy/KTNFLzklNzFMos7TUAyNdSyDQLagsSS0uUdAwMjC01DU01DUwUjA0tDK1sDIw0GQAAFSoEKQ=
</Array> </Array>
</FieldData> </FieldData>
<Piece Extent="0 8 0 5 0 4"> <Piece Extent="0 8 0 5 0 4">
@ -11,7 +11,7 @@
</PointData> </PointData>
<CellData> <CellData>
<DataArray type="Int64" Name="material" format="binary" RangeMin="1" RangeMax="2"> <DataArray type="Int64" Name="material" format="binary" RangeMin="1" RangeMax="2">
AQAAAACAAAAABQAAGQAAAA==eF5jZIAAxlF6lB4AmmmUHqUHkAYA/M8A8Q== AQAAAACAAAAABQAAKwAAAA==eF5jZIAAxlGaLJoJjcYlTqw6Qvpx2U+pu0iVJ8QnJD5Kj9KDgQYAUc4BDA==
</DataArray> </DataArray>
</CellData> </CellData>
</Piece> </Piece>

View File

@ -3,7 +3,7 @@
<ImageData WholeExtent="0 8 0 5 0 4" Origin="0 0 0" Spacing="0.000001 0.0000010000000000000002 0.000001" Direction="1 0 0 0 1 0 0 0 1"> <ImageData WholeExtent="0 8 0 5 0 4" Origin="0 0 0" Spacing="0.000001 0.0000010000000000000002 0.000001" Direction="1 0 0 0 1 0 0 0 1">
<FieldData> <FieldData>
<Array type="String" Name="comments" NumberOfTuples="1" format="binary"> <Array type="String" Name="comments" NumberOfTuples="1" format="binary">
AQAAAACAAAA+AAAAQQAAAA==eF5LScxNLM7Wc0/Nz9VLzklNzFMos7TUAyNdSyDQLagsSS0uUdAwMjC01DU01DUwUjA0tDK1sDIw0GQAAFT8EKY= AQAAAACAAAA+AAAAQQAAAA==eF5LScxNLM7Wcy/KTNFLzklNzFMos7TUAyNdSyDQLagsSS0uUdAwMjC01DU01DUwUjA0tDK1sDIw0GQAAFSoEKQ=
</Array> </Array>
</FieldData> </FieldData>
<Piece Extent="0 8 0 5 0 4"> <Piece Extent="0 8 0 5 0 4">
@ -11,7 +11,7 @@
</PointData> </PointData>
<CellData> <CellData>
<DataArray type="Int64" Name="material" format="binary" RangeMin="1" RangeMax="2"> <DataArray type="Int64" Name="material" format="binary" RangeMin="1" RangeMax="2">
AQAAAACAAAAABQAAGwAAAA==eF5jZIAAxlF6lB4AmmmUpogeDUfKaAD7jwDw AQAAAACAAAAABQAAPwAAAA==eF5jZIAAxlGaLJqJAE2pPlx8atG4zCXkXmLFaeXuURqVJhQfhNIhLj4h9YTil1h7COkn5D9C+nGJAwBKngD7
</DataArray> </DataArray>
</CellData> </CellData>
</Piece> </Piece>

View File

@ -1,19 +0,0 @@
<?xml version="1.0"?>
<VTKFile type="ImageData" version="0.1" byte_order="LittleEndian" header_type="UInt32" compressor="vtkZLibDataCompressor">
<ImageData WholeExtent="0 8 0 5 0 4" Origin="0 0 0" Spacing="0.000001 0.0000010000000000000002 0.000001" Direction="1 0 0 0 1 0 0 0 1">
<FieldData>
<Array type="String" Name="comments" NumberOfTuples="1" format="binary">
AQAAAACAAAA+AAAAQQAAAA==eF5LScxNLM7Wc0/Nz9VLzklNzFMos7TUAyNdSyDQLagsSS0uUdAwMjC01DU01DUwUjA0tDK1sDIw0GQAAFT8EKY=
</Array>
</FieldData>
<Piece Extent="0 8 0 5 0 4">
<PointData>
</PointData>
<CellData>
<DataArray type="Int64" Name="material" format="binary" RangeMin="1" RangeMax="41">
AQAAAACAAAAABQAAagAAAA==eF7t0rkOglAARFExLrgCKuKuqLj8/w9acCoSY7B+05x+cqNOvSj4l92GPfY54JAxRxxzwilnnDNhyowLLrlizjULbrjljnseeOSJZ15Y8sob76z44JMvvtn8L9jObz2GDuv96vADk5QHBg==
</DataArray>
</CellData>
</Piece>
</ImageData>
</VTKFile>

View File

@ -1,19 +0,0 @@
<?xml version="1.0"?>
<VTKFile type="ImageData" version="0.1" byte_order="LittleEndian" header_type="UInt32" compressor="vtkZLibDataCompressor">
<ImageData WholeExtent="0 8 0 5 0 4" Origin="0 0 0" Spacing="0.000001 0.0000010000000000000002 0.000001" Direction="1 0 0 0 1 0 0 0 1">
<FieldData>
<Array type="String" Name="comments" NumberOfTuples="1" format="binary">
AQAAAACAAAA+AAAAQQAAAA==eF5LScxNLM7Wc0/Nz9VLzklNzFMos7TUAyNdSyDQLagsSS0uUdAwMjC01DU01DUwUjA0tDK1sDIw0GQAAFT8EKY=
</Array>
</FieldData>
<Piece Extent="0 8 0 5 0 4">
<PointData>
</PointData>
<CellData>
<DataArray type="Int64" Name="material" format="binary" RangeMin="1" RangeMax="2">
AQAAAACAAAAABQAAIgAAAA==eF5jZIAAxlGaLJoJjSakntr6hzqN7v9RepSmJw0AC04A9Q==
</DataArray>
</CellData>
</Piece>
</ImageData>
</VTKFile>

View File

@ -1,19 +0,0 @@
<?xml version="1.0"?>
<VTKFile type="ImageData" version="0.1" byte_order="LittleEndian" header_type="UInt32" compressor="vtkZLibDataCompressor">
<ImageData WholeExtent="0 8 0 5 0 4" Origin="0 0 0" Spacing="0.000001 0.0000010000000000000002 0.000001" Direction="1 0 0 0 1 0 0 0 1">
<FieldData>
<Array type="String" Name="comments" NumberOfTuples="1" format="binary">
AQAAAACAAAA+AAAAQQAAAA==eF5LScxNLM7Wc0/Nz9VLzklNzFMos7TUAyNdSyDQLagsSS0uUdAwMjC01DU01DUwUjA0tDK1sDIw0GQAAFT8EKY=
</Array>
</FieldData>
<Piece Extent="0 8 0 5 0 4">
<PointData>
</PointData>
<CellData>
<DataArray type="Int64" Name="material" format="binary" RangeMin="1" RangeMax="2">
AQAAAACAAAAABQAALwAAAA==eF5jZIAAxlGaLJoJjSakHpc+cvUTUkdrmlL3j9KU0dROF5TqH2iaVPcDAALOANU=
</DataArray>
</CellData>
</Piece>
</ImageData>
</VTKFile>

View File

@ -1,19 +0,0 @@
<?xml version="1.0"?>
<VTKFile type="ImageData" version="0.1" byte_order="LittleEndian" header_type="UInt32" compressor="vtkZLibDataCompressor">
<ImageData WholeExtent="0 8 0 5 0 4" Origin="0 0 0" Spacing="0.000001 0.0000010000000000000002 0.000001" Direction="1 0 0 0 1 0 0 0 1">
<FieldData>
<Array type="String" Name="comments" NumberOfTuples="1" format="binary">
AQAAAACAAAA+AAAAQQAAAA==eF5LScxNLM7Wc0/Nz9VLzklNzFMos7TUAyNdSyDQLagsSS0uUdAwMjC01DU01DUwUjA0tDK1sDIw0GQAAFT8EKY=
</Array>
</FieldData>
<Piece Extent="0 8 0 5 0 4">
<PointData>
</PointData>
<CellData>
<DataArray type="Int64" Name="material" format="binary" RangeMin="1" RangeMax="41">
AQAAAACAAAAABQAAcQAAAA==eF7t0rkOglAUBFAxKu6igvsKrv//gxYcm9fQGEPBNKe6yc1kolaZqPEndthljzH7HHDIEceccMoZE8654JIpM6645oZb7rjngUeeeOaFV+YseOOdDz754pthf+3Aqr7rdv9vw3+/NjssU7XDD0/8BuQ=
</DataArray>
</CellData>
</Piece>
</ImageData>
</VTKFile>

View File

@ -1,19 +0,0 @@
<?xml version="1.0"?>
<VTKFile type="ImageData" version="0.1" byte_order="LittleEndian" header_type="UInt32" compressor="vtkZLibDataCompressor">
<ImageData WholeExtent="0 8 0 5 0 4" Origin="0 0 0" Spacing="0.000001 0.0000010000000000000002 0.000001" Direction="1 0 0 0 1 0 0 0 1">
<FieldData>
<Array type="String" Name="comments" NumberOfTuples="1" format="binary">
AQAAAACAAAA+AAAAQQAAAA==eF5LScxNLM7Wc0/Nz9VLzklNzFMos7TUAyNdSyDQLagsSS0uUdAwMjC01DU01DUwUjA0tDK1sDIw0GQAAFT8EKY=
</Array>
</FieldData>
<Piece Extent="0 8 0 5 0 4">
<PointData>
</PointData>
<CellData>
<DataArray type="Int64" Name="material" format="binary" RangeMin="1" RangeMax="41">
AQAAAACAAAAABQAAYQAAAA==eF7t0scVglAAAEHgqZgBA2ZExdR/gx6YCpDj38s0sEnUlgR7ccAhR0w55oRTzjjngktmzFlwxTU33LLkjnseeOSJZ15Y8cqaN975YMMnX3zzwy/j4F+GD9u6fvgD+gwHCA==
</DataArray>
</CellData>
</Piece>
</ImageData>
</VTKFile>

View File

@ -1,19 +0,0 @@
<?xml version="1.0"?>
<VTKFile type="ImageData" version="0.1" byte_order="LittleEndian" header_type="UInt32" compressor="vtkZLibDataCompressor">
<ImageData WholeExtent="0 8 0 5 0 4" Origin="0 0 0" Spacing="0.000001 0.0000010000000000000002 0.000001" Direction="1 0 0 0 1 0 0 0 1">
<FieldData>
<Array type="String" Name="comments" NumberOfTuples="1" format="binary">
AQAAAACAAAA+AAAAQQAAAA==eF5LScxNLM7Wc0/Nz9VLzklNzFMos7TUAyNdSyDQLagsSS0uUdAwMjC01DU01DUwUjA0tDK1sDIw0GQAAFT8EKY=
</Array>
</FieldData>
<Piece Extent="0 8 0 5 0 4">
<PointData>
</PointData>
<CellData>
<DataArray type="Int64" Name="material" format="binary" RangeMin="2" RangeMax="41">
AQAAAACAAAAABQAAZAAAAA==eF7t0rcSglAARFEHE0bAgBkE8///oAWnF8b2bXP6nRv1mkXBv+xzwCFHHDPmhFPOOOeCSyZMmXHFNTfcMueOex545IlnXliw5JUVa95454NPvvjmh79+DXYzdNisbYdfSqMHMg==
</DataArray>
</CellData>
</Piece>
</ImageData>
</VTKFile>

View File

@ -1,19 +0,0 @@
<?xml version="1.0"?>
<VTKFile type="ImageData" version="0.1" byte_order="LittleEndian" header_type="UInt32" compressor="vtkZLibDataCompressor">
<ImageData WholeExtent="0 8 0 5 0 4" Origin="0 0 0" Spacing="0.000001 0.0000010000000000000002 0.000001" Direction="1 0 0 0 1 0 0 0 1">
<FieldData>
<Array type="String" Name="comments" NumberOfTuples="1" format="binary">
AQAAAACAAAA+AAAAQQAAAA==eF5LScxNLM7Wc0/Nz9VLzklNzFMos7TUAyNdSyDQLagsSS0uUdAwMjC01DU01DUwUjA0tDK1sDIw0GQAAFT8EKY=
</Array>
</FieldData>
<Piece Extent="0 8 0 5 0 4">
<PointData>
</PointData>
<CellData>
<DataArray type="Int64" Name="material" format="binary" RangeMin="1" RangeMax="2">
AQAAAACAAAAABQAAIAAAAA==eF5jZIAAxlF6lB4AmokAPdj1DzRNyP2jNH4aAMufANU=
</DataArray>
</CellData>
</Piece>
</ImageData>
</VTKFile>

View File

@ -1,19 +0,0 @@
<?xml version="1.0"?>
<VTKFile type="ImageData" version="0.1" byte_order="LittleEndian" header_type="UInt32" compressor="vtkZLibDataCompressor">
<ImageData WholeExtent="0 8 0 5 0 4" Origin="0 0 0" Spacing="0.000001 0.0000010000000000000002 0.000001" Direction="1 0 0 0 1 0 0 0 1">
<FieldData>
<Array type="String" Name="comments" NumberOfTuples="1" format="binary">
AQAAAACAAAA+AAAAQQAAAA==eF5LScxNLM7Wc0/Nz9VLzklNzFMos7TUAyNdSyDQLagsSS0uUdAwMjC01DU01DUwUjA0tDK1sDIw0GQAAFT8EKY=
</Array>
</FieldData>
<Piece Extent="0 8 0 5 0 4">
<PointData>
</PointData>
<CellData>
<DataArray type="Int64" Name="material" format="binary" RangeMin="1" RangeMax="2">
AQAAAACAAAAABQAAMAAAAA==eF5jYoAAJhw0IwEalz566aeUptT+oa6fUppS+4e6fkppSu0f6voppSm1HwBAngDh
</DataArray>
</CellData>
</Piece>
</ImageData>
</VTKFile>

View File

@ -102,3 +102,11 @@ class TestCrystal:
assert [len(s) for s in crystal.kinematics('twin')['direction']] == length assert [len(s) for s in crystal.kinematics('twin')['direction']] == length
assert [len(s) for s in crystal.kinematics('twin')['plane']] == length assert [len(s) for s in crystal.kinematics('twin')['plane']] == length
@pytest.mark.parametrize('crystal', [Crystal(lattice='cF'),
Crystal(lattice='cI'),
Crystal(lattice='hP'),
Crystal(lattice='tI',c=1.2)])
def test_related(self,crystal):
for r in crystal.orientation_relationships:
crystal.relation_operations(r)

View File

@ -26,6 +26,14 @@ def default():
np.arange(1,41))).reshape(8,5,4,order='F') np.arange(1,41))).reshape(8,5,4,order='F')
return Grid(x,[8e-6,5e-6,4e-6]) return Grid(x,[8e-6,5e-6,4e-6])
@pytest.fixture
def random():
"""Simple geometry."""
size = (1+np.random.rand(3))*1e-5
cells = np.random.randint(10,20,3)
s = seeds.from_random(size,np.random.randint(5,25),cells)
return Grid.from_Voronoi_tessellation(cells,size,s)
@pytest.fixture @pytest.fixture
def ref_path(ref_path_base): def ref_path(ref_path_base):
"""Directory containing reference results.""" """Directory containing reference results."""
@ -157,17 +165,26 @@ class TestGrid:
default.flip(directions) default.flip(directions)
@pytest.mark.parametrize('stencil',[1,2,3,4]) @pytest.mark.parametrize('distance',[1.,np.sqrt(3)])
@pytest.mark.parametrize('selection',[None,[1],[1,2,3]]) @pytest.mark.parametrize('selection',[None,1,[1],[1,2,3]])
@pytest.mark.parametrize('periodic',[True,False]) @pytest.mark.parametrize('periodic',[True,False])
def test_clean(self,default,update,ref_path,stencil,selection,periodic): def test_clean_reference(self,default,update,ref_path,distance,selection,periodic):
current = default.clean(stencil,selection,periodic) current = default.clean(distance,selection,periodic=periodic,rng_seed=0)
reference = ref_path/f'clean_{stencil}_{"+".join(map(str,[None] if selection is None else selection))}_{periodic}.vti' reference = ref_path/f'clean_{distance}_{"+".join(map(str,util.aslist(selection)))}_{periodic}.vti'
if update and stencil > 1: if update:
current.save(reference) current.save(reference)
assert grid_equal(Grid.load(reference) if stencil > 1 else default, assert grid_equal(Grid.load(reference),current)
current
) @pytest.mark.parametrize('selection',[list(np.random.randint(1,20,6)),set(np.random.randint(1,20,6)),np.random.randint(1,20,6)])
@pytest.mark.parametrize('invert',[True,False])
def test_clean_invert(self,default,selection,invert):
selection_inverse = set(default.material.flatten()) - set(selection)
assert default.clean(selection=selection,invert_selection=invert,rng_seed=0) == \
default.clean(selection=selection_inverse,invert_selection=not invert,rng_seed=0)
def test_clean_selection_empty(self,random):
assert random.clean(selection=None,invert_selection=True,rng_seed=0) == random.clean(rng_seed=0) and \
random.clean(selection=None,invert_selection=False,rng_seed=0) == random.clean(rng_seed=0)
@pytest.mark.parametrize('cells',[ @pytest.mark.parametrize('cells',[
@ -211,6 +228,11 @@ class TestGrid:
modified.substitute(np.arange(default.material.max())+1+offset, modified.substitute(np.arange(default.material.max())+1+offset,
np.arange(default.material.max())+1)) np.arange(default.material.max())+1))
def test_substitute_integer_list(self,random):
f = np.random.randint(30)
t = np.random.randint(30)
assert random.substitute(f,t) == random.substitute([f],[t])
def test_substitute_invariant(self,default): def test_substitute_invariant(self,default):
f = np.unique(default.material.flatten())[:np.random.randint(1,default.material.max())] f = np.unique(default.material.flatten())[:np.random.randint(1,default.material.max())]
t = np.random.permutation(f) t = np.random.permutation(f)
@ -302,31 +324,43 @@ class TestGrid:
assert grid_equal(G_1,G_2) assert grid_equal(G_1,G_2)
@pytest.mark.parametrize('trigger',[[1],[]]) @pytest.mark.parametrize('selection',[1,None])
def test_vicinity_offset(self,trigger): def test_vicinity_offset(self,selection):
offset = np.random.randint(2,4) offset = np.random.randint(2,4)
vicinity = np.random.randint(2,4) distance = np.random.randint(2,4)
g = np.random.randint(28,40,(3)) g = np.random.randint(28,40,(3))
m = np.ones(g,'i') m = np.ones(g,'i')
x = (g*np.random.permutation(np.array([.5,1,1]))).astype('i') x = (g*np.random.permutation(np.array([.5,1,1]))).astype(int)
m[slice(0,x[0]),slice(0,x[1]),slice(0,x[2])] = 2 m[slice(0,x[0]),slice(0,x[1]),slice(0,x[2])] = 2
m2 = m.copy() m2 = m.copy()
for i in [0,1,2]: for i in [0,1,2]:
m2[(np.roll(m,+vicinity,i)-m)!=0] += offset m2[(np.roll(m,+distance,i)-m)!=0] += offset
m2[(np.roll(m,-vicinity,i)-m)!=0] += offset m2[(np.roll(m,-distance,i)-m)!=0] += offset
if len(trigger) > 0: if selection == 1:
m2[m==1] = 1 m2[m==1] = 1
grid = Grid(m,np.random.rand(3)).vicinity_offset(vicinity,offset,trigger=trigger) grid = Grid(m,np.random.rand(3)).vicinity_offset(distance,offset,selection=selection)
assert np.all(m2==grid.material) assert np.all(m2==grid.material)
@pytest.mark.parametrize('selection',[list(np.random.randint(1,20,6)),set(np.random.randint(1,20,6)),np.random.randint(1,20,6)])
@pytest.mark.parametrize('invert',[True,False])
def test_vicinit_offset_invert(self,random,selection,invert):
selection_inverse = set(random.material.flatten()) - set(selection)
assert selection_inverse == set() or \
(random.vicinity_offset(selection=selection,invert_selection=invert) ==
random.vicinity_offset(selection=selection_inverse,invert_selection=not invert))
def test_vicinity_offset_selection_empty(self,random):
assert random.vicinity_offset(selection=None,invert_selection=False) == random.vicinity_offset() and \
random.vicinity_offset(selection=None,invert_selection=True ) == random.vicinity_offset()
@pytest.mark.parametrize('periodic',[True,False]) @pytest.mark.parametrize('periodic',[True,False])
def test_vicinity_offset_invariant(self,default,periodic): def test_vicinity_offset_invariant(self,default,periodic):
offset = default.vicinity_offset(trigger=[default.material.max()+1, offset = default.vicinity_offset(selection=[default.material.max()+1,
default.material.min()-1]) default.material.min()-1])
assert np.all(offset.material==default.material) assert np.all(offset.material==default.material)

View File

@ -69,8 +69,8 @@ class TestResult:
@pytest.mark.parametrize('what',['increments','times','phases','fields']) # ToDo: discuss homogenizations @pytest.mark.parametrize('what',['increments','times','phases','fields']) # ToDo: discuss homogenizations
def test_view_none(self,default,what): def test_view_none(self,default,what):
n0 = default.view(what,False) n0 = default.view(**{what:False})
n1 = default.view(what,[]) n1 = default.view(**{what:[]})
label = 'increments' if what == 'times' else what label = 'increments' if what == 'times' else what
@ -79,29 +79,25 @@ class TestResult:
@pytest.mark.parametrize('what',['increments','times','phases','fields']) # ToDo: discuss homogenizations @pytest.mark.parametrize('what',['increments','times','phases','fields']) # ToDo: discuss homogenizations
def test_view_more(self,default,what): def test_view_more(self,default,what):
empty = default.view(what,False) empty = default.view(**{what:False})
a = empty.view_more(what,'*').get('F') a = empty.view_more(**{what:'*'}).get('F')
b = empty.view_more(what,True).get('F') b = empty.view_more(**{what:True}).get('F')
assert dict_equal(a,b) assert dict_equal(a,b)
@pytest.mark.parametrize('what',['increments','times','phases','fields']) # ToDo: discuss homogenizations @pytest.mark.parametrize('what',['increments','times','phases','fields']) # ToDo: discuss homogenizations
def test_view_less(self,default,what): def test_view_less(self,default,what):
full = default.view(what,True) full = default.view(**{what:True})
n0 = full.view_less(what,'*') n0 = full.view_less(**{what:'*'})
n1 = full.view_less(what,True) n1 = full.view_less(**{what:True})
label = 'increments' if what == 'times' else what label = 'increments' if what == 'times' else what
assert n0.get('F') is n1.get('F') is None and \ assert n0.get('F') is n1.get('F') is None and \
len(n0.visible[label]) == len(n1.visible[label]) == 0 len(n0.visible[label]) == len(n1.visible[label]) == 0
def test_view_invalid(self,default):
with pytest.raises(AttributeError):
default.view('invalid',True)
def test_add_invalid(self,default): def test_add_invalid(self,default):
default.add_absolute('xxxx') default.add_absolute('xxxx')
@ -469,7 +465,7 @@ class TestResult:
def test_get(self,update,request,ref_path,view,output,flatten,prune): def test_get(self,update,request,ref_path,view,output,flatten,prune):
result = Result(ref_path/'4grains2x4x3_compressionY.hdf5') result = Result(ref_path/'4grains2x4x3_compressionY.hdf5')
for key,value in view.items(): for key,value in view.items():
result = result.view(key,value) result = result.view(**{key:value})
fname = request.node.name fname = request.node.name
cur = result.get(output,flatten,prune) cur = result.get(output,flatten,prune)
@ -494,7 +490,7 @@ class TestResult:
def test_place(self,update,request,ref_path,view,output,flatten,prune,constituents): def test_place(self,update,request,ref_path,view,output,flatten,prune,constituents):
result = Result(ref_path/'4grains2x4x3_compressionY.hdf5') result = Result(ref_path/'4grains2x4x3_compressionY.hdf5')
for key,value in view.items(): for key,value in view.items():
result = result.view(key,value) result = result.view(**{key:value})
fname = request.node.name fname = request.node.name
cur = result.place(output,flatten,prune,constituents) cur = result.place(output,flatten,prune,constituents)

View File

@ -117,6 +117,10 @@ class TestUtil:
def test_decorate(self,style): def test_decorate(self,style):
assert 'DAMASK' in style('DAMASK') assert 'DAMASK' in style('DAMASK')
@pytest.mark.parametrize('lst',[1,[1,2],set([1,2,3]),np.arange(4)])
def test_aslist(self,lst):
assert len(util.aslist(lst)) > 0
@pytest.mark.parametrize('complete',[True,False]) @pytest.mark.parametrize('complete',[True,False])
def test_D3D_base_group(self,tmp_path,complete): def test_D3D_base_group(self,tmp_path,complete):
base_group = ''.join(random.choices('DAMASK', k=10)) base_group = ''.join(random.choices('DAMASK', k=10))

View File

@ -70,9 +70,8 @@ subroutine DAMASK_interface_init
external :: & external :: &
quit quit
print'(/,1x,a)', '<<<+- DAMASK_interface init -+>>>'
if(worldrank == 0) open(OUTPUT_UNIT, encoding='UTF-8') ! for special characters in output print'(/,1x,a)', '<<<+- DAMASK_interface init -+>>>'
! http://patorjk.com/software/taag/#p=display&f=Lean&t=DAMASK%203 ! http://patorjk.com/software/taag/#p=display&f=Lean&t=DAMASK%203
#ifdef DEBUG #ifdef DEBUG

View File

@ -56,9 +56,6 @@ program DAMASK_grid
!-------------------------------------------------------------------------------------------------- !--------------------------------------------------------------------------------------------------
! loop variables, convergence etc. ! loop variables, convergence etc.
real(pReal), dimension(3,3), parameter :: &
ones = 1.0_pReal, &
zeros = 0.0_pReal
integer, parameter :: & integer, parameter :: &
subStepFactor = 2 !< for each substep, divide the last time increment by 2.0 subStepFactor = 2 !< for each substep, divide the last time increment by 2.0
real(pReal) :: & real(pReal) :: &

View File

@ -103,7 +103,7 @@ subroutine discretization_grid_init(restart)
print'(/,1x,a,i0,a,i0,a,i0)', 'cells: ', cells(1), ' × ', cells(2), ' × ', cells(3) print'(/,1x,a,i0,a,i0,a,i0)', 'cells: ', cells(1), ' × ', cells(2), ' × ', cells(3)
print '(1x,a,es8.2,a,es8.2,a,es8.2,a)', 'size: ', geomSize(1), ' × ', geomSize(2), ' × ', geomSize(3), ' m³' print '(1x,a,es8.2,a,es8.2,a,es8.2,a)', 'size: ', geomSize(1), ' × ', geomSize(2), ' × ', geomSize(3), ' m³'
print '(1x,a,es8.2,a,es8.2,a,es8.2,a)', 'origin: ', origin(1), ' ', origin(2), ' ', origin(3), ' m' print '(1x,a,es9.2,a,es9.2,a,es9.2,a)', 'origin: ', origin(1), ' ', origin(2), ' ', origin(3), ' m'
if (worldsize>cells(3)) call IO_error(894, ext_msg='number of processes exceeds cells(3)') if (worldsize>cells(3)) call IO_error(894, ext_msg='number of processes exceeds cells(3)')

View File

@ -256,7 +256,7 @@ subroutine spectral_utilities_init
!-------------------------------------------------------------------------------------------------- !--------------------------------------------------------------------------------------------------
! general initialization of FFTW (see manual on fftw.org for more details) ! general initialization of FFTW (see manual on fftw.org for more details)
if (pReal /= C_DOUBLE .or. kind(1) /= C_INT) error stop 'C and Fortran datatypes do not match' if (pReal /= C_DOUBLE .or. kind(1) /= C_INT) error stop 'C and Fortran datatypes do not match'
call fftw_set_timelimit(num_grid%get_asFloat('fftw_timelimit',defaultVal=-1.0_pReal)) call fftw_set_timelimit(num_grid%get_asFloat('fftw_timelimit',defaultVal=300.0_pReal))
print'(/,1x,a)', 'FFTW initialized'; flush(IO_STDOUT) print'(/,1x,a)', 'FFTW initialized'; flush(IO_STDOUT)

View File

@ -21,6 +21,15 @@ module homogenization
implicit none implicit none
private private
type :: tState
integer :: &
sizeState = 0 !< size of state
! http://stackoverflow.com/questions/3948210
real(pReal), pointer, dimension(:,:), contiguous :: & !< is basically an allocatable+target, but in a type needs to be pointer
state0, &
state
end type
enum, bind(c); enumerator :: & enum, bind(c); enumerator :: &
THERMAL_UNDEFINED_ID, & THERMAL_UNDEFINED_ID, &
THERMAL_PASS_ID, & THERMAL_PASS_ID, &

View File

@ -4,7 +4,8 @@
!-------------------------------------------------------------------------------------------------- !--------------------------------------------------------------------------------------------------
module parallelization module parallelization
use, intrinsic :: ISO_fortran_env, only: & use, intrinsic :: ISO_fortran_env, only: &
OUTPUT_UNIT OUTPUT_UNIT, &
ERROR_UNIT
#ifdef PETSC #ifdef PETSC
#include <petsc/finclude/petscsys.h> #include <petsc/finclude/petscsys.h>
@ -86,17 +87,28 @@ subroutine parallelization_init
if (err_MPI /= 0_MPI_INTEGER_KIND) & if (err_MPI /= 0_MPI_INTEGER_KIND) &
error stop 'Could not determine worldrank' error stop 'Could not determine worldrank'
if (worldrank == 0) then #ifdef LOGFILE
print'(/,1x,a)', '<<<+- parallelization init -+>>>' write(rank_str,'(i4.4)') worldrank
open(OUTPUT_UNIT,file='out.'//rank_str,status='replace',encoding='UTF-8')
call MPI_Get_library_version(MPI_library_version,devNull,err_MPI) open(ERROR_UNIT,file='error.'//rank_str,status='replace',encoding='UTF-8')
print'(/,1x,a)', trim(MPI_library_version) #else
call MPI_Get_version(version,subversion,err_MPI) if (worldrank /= 0) then
print'(1x,a,i0,a,i0)', 'MPI standard: ',version,'.',subversion close(OUTPUT_UNIT) ! disable output
#ifdef _OPENMP open(OUTPUT_UNIT,file='/dev/null',status='replace') ! close() alone will leave some temp files in cwd
print'(1x,a,i0)', 'OpenMP version: ',openmp_version else
open(OUTPUT_UNIT,encoding='UTF-8') ! for special characters in output
endif
#endif
print'(/,1x,a)', '<<<+- parallelization init -+>>>'
call MPI_Get_library_version(MPI_library_version,devNull,err_MPI)
print'(/,1x,a)', trim(MPI_library_version)
call MPI_Get_version(version,subversion,err_MPI)
print'(1x,a,i0,a,i0)', 'MPI standard: ',version,'.',subversion
#ifdef _OPENMP
print'(1x,a,i0)', 'OpenMP version: ',openmp_version
#endif #endif
end if
call MPI_Comm_size(MPI_COMM_WORLD,worldsize,err_MPI) call MPI_Comm_size(MPI_COMM_WORLD,worldsize,err_MPI)
if (err_MPI /= 0_MPI_INTEGER_KIND) & if (err_MPI /= 0_MPI_INTEGER_KIND) &
@ -121,12 +133,6 @@ subroutine parallelization_init
if (typeSize*8_MPI_INTEGER_KIND /= int(storage_size(0.0_pReal),MPI_INTEGER_KIND)) & if (typeSize*8_MPI_INTEGER_KIND /= int(storage_size(0.0_pReal),MPI_INTEGER_KIND)) &
error stop 'Mismatch between MPI_DOUBLE and DAMASK pReal' error stop 'Mismatch between MPI_DOUBLE and DAMASK pReal'
if (worldrank /= 0) then
close(OUTPUT_UNIT) ! disable output
write(rank_str,'(i4.4)') worldrank ! use for MPI debug filenames
open(OUTPUT_UNIT,file='/dev/null',status='replace') ! close() alone will leave some temp files in cwd
endif
!$ call get_environment_variable(name='OMP_NUM_THREADS',value=NumThreadsString,STATUS=got_env) !$ call get_environment_variable(name='OMP_NUM_THREADS',value=NumThreadsString,STATUS=got_env)
!$ if(got_env /= 0) then !$ if(got_env /= 0) then
!$ print'(1x,a)', 'Could not get $OMP_NUM_THREADS, using default' !$ print'(1x,a)', 'Could not get $OMP_NUM_THREADS, using default'

View File

@ -22,6 +22,32 @@ module phase
implicit none implicit none
private private
type :: tState
integer :: &
sizeState = 0, & !< size of state
sizeDotState = 0, & !< size of dot state, i.e. state(1:sizeDot) follows time evolution by dotState rates
offsetDeltaState = 0, & !< index offset of delta state
sizeDeltaState = 0 !< size of delta state, i.e. state(offset+1:offset+sizeDelta) follows time evolution by deltaState increments
real(pReal), allocatable, dimension(:) :: &
atol
! http://stackoverflow.com/questions/3948210
real(pReal), pointer, dimension(:,:), contiguous :: & !< is basically an allocatable+target, but in a type needs to be pointer
state0, &
state, & !< state
dotState, & !< rate of state change
deltaState !< increment of state change
real(pReal), pointer, dimension(:,:) :: &
deltaState2
end type
type, extends(tState) :: tPlasticState
logical :: nonlocal = .false.
end type
type :: tSourceState
type(tState), dimension(:), allocatable :: p !< tState for each active source mechanism in a phase
end type
character(len=2), allocatable, dimension(:) :: phase_lattice character(len=2), allocatable, dimension(:) :: phase_lattice
real(pReal), allocatable, dimension(:) :: phase_cOverA real(pReal), allocatable, dimension(:) :: phase_cOverA

View File

@ -920,11 +920,11 @@ subroutine results(group,ph)
call results_writeDataset(phase_mechanical_S(ph)%data,group//'/mechanical/','S', & call results_writeDataset(phase_mechanical_S(ph)%data,group//'/mechanical/','S', &
'second Piola-Kirchhoff stress','Pa') 'second Piola-Kirchhoff stress','Pa')
case('O') case('O')
call results_writeDataset(to_quaternion(phase_O(ph)%data),group//'/mechanical',output_mechanical(ph)%label(ou),& call results_writeDataset(to_quaternion(phase_O(ph)%data),group//'/mechanical','O', &
'crystal orientation as quaternion','q_0 (q_1 q_2 q_3)') 'crystal orientation as quaternion','q_0 (q_1 q_2 q_3)')
call results_addAttribute('lattice',phase_lattice(ph),group//'/mechanical/'//output_mechanical(ph)%label(ou)) call results_addAttribute('lattice',phase_lattice(ph),group//'/mechanical/O')
if (any(phase_lattice(ph) == ['hP', 'tI'])) & if (any(phase_lattice(ph) == ['hP', 'tI'])) &
call results_addAttribute('c/a',phase_cOverA(ph),group//'/mechanical/'//output_mechanical(ph)%label(ou)) call results_addAttribute('c/a',phase_cOverA(ph),group//'/mechanical/O')
end select end select
end do end do

View File

@ -31,31 +31,6 @@ module prec
real(pReal), parameter :: tol_math_check = 1.0e-8_pReal !< tolerance for internal math self-checks (rotation) real(pReal), parameter :: tol_math_check = 1.0e-8_pReal !< tolerance for internal math self-checks (rotation)
type :: tState
integer :: &
sizeState = 0, & !< size of state
sizeDotState = 0, & !< size of dot state, i.e. state(1:sizeDot) follows time evolution by dotState rates
offsetDeltaState = 0, & !< index offset of delta state
sizeDeltaState = 0 !< size of delta state, i.e. state(offset+1:offset+sizeDelta) follows time evolution by deltaState increments
real(pReal), allocatable, dimension(:) :: &
atol
! http://stackoverflow.com/questions/3948210
real(pReal), pointer, dimension(:,:), contiguous :: & !< is basically an allocatable+target, but in a type needs to be pointer
state0, &
state, & !< state
dotState, & !< rate of state change
deltaState !< increment of state change
real(pReal), pointer, dimension(:,:) :: &
deltaState2
end type
type, extends(tState) :: tPlasticState
logical :: nonlocal = .false.
end type
type :: tSourceState
type(tState), dimension(:), allocatable :: p !< tState for each active source mechanism in a phase
end type
real(pReal), private, parameter :: PREAL_EPSILON = epsilon(0.0_pReal) !< minimum positive number such that 1.0 + EPSILON /= 1.0. real(pReal), private, parameter :: PREAL_EPSILON = epsilon(0.0_pReal) !< minimum positive number such that 1.0 + EPSILON /= 1.0.
real(pReal), private, parameter :: PREAL_MIN = tiny(0.0_pReal) !< smallest normalized floating point number real(pReal), private, parameter :: PREAL_MIN = tiny(0.0_pReal) !< smallest normalized floating point number

View File

@ -388,14 +388,11 @@ subroutine results_writeVectorDataset_real(dataset,group,label,description,SIuni
integer(HID_T) :: groupHandle integer(HID_T) :: groupHandle
if (present(systems)) then
if (size(systems)*size(dataset,2) == 0 ) return !ToDo: maybe also implement for other results_write (not sure about scalar)
end if
groupHandle = results_openGroup(group) groupHandle = results_openGroup(group)
call HDF5_write(dataset,groupHandle,label) call HDF5_write(dataset,groupHandle,label)
call executionStamp(group//'/'//label,description,SIunit) call executionStamp(group//'/'//label,description,SIunit)
if (present(systems)) call HDF5_addAttribute(resultsFile,'systems',systems,group//'/'//label) if (present(systems) .and. HDF5_objectExists(groupHandle,label)) &
call HDF5_addAttribute(resultsFile,'systems',systems,group//'/'//label)
call HDF5_closeGroup(groupHandle) call HDF5_closeGroup(groupHandle)
end subroutine results_writeVectorDataset_real end subroutine results_writeVectorDataset_real
@ -454,14 +451,11 @@ subroutine results_writeVectorDataset_int(dataset,group,label,description,SIunit
integer(HID_T) :: groupHandle integer(HID_T) :: groupHandle
if (present(systems)) then
if (size(systems)*size(dataset,2) == 0 ) return !ToDo: maybe also implement for other results_write (not sure about scalar)
end if
groupHandle = results_openGroup(group) groupHandle = results_openGroup(group)
call HDF5_write(dataset,groupHandle,label) call HDF5_write(dataset,groupHandle,label)
call executionStamp(group//'/'//label,description,SIunit) call executionStamp(group//'/'//label,description,SIunit)
if (present(systems)) call HDF5_addAttribute(resultsFile,'systems',systems,group//'/'//label) if (present(systems) .and. HDF5_objectExists(groupHandle,label)) &
call HDF5_addAttribute(resultsFile,'systems',systems,group//'/'//label)
call HDF5_closeGroup(groupHandle) call HDF5_closeGroup(groupHandle)
end subroutine results_writeVectorDataset_int end subroutine results_writeVectorDataset_int