Merge remote-tracking branch 'origin/development' into 256-grid-geometry-displacement-reconstruction
This commit is contained in:
commit
5b8194d8eb
|
@ -12,12 +12,12 @@
|
||||||
*.pbz2 binary
|
*.pbz2 binary
|
||||||
|
|
||||||
# ignore files from MSC.Marc in language statistics
|
# ignore files from MSC.Marc in language statistics
|
||||||
install/MarcMentat/** linguist-vendored
|
install/MarcMentat/** linguist-vendored
|
||||||
src/Marc/include/* linguist-vendored
|
src/Marc/include/* linguist-vendored
|
||||||
install/MarcMentat/MSC_modifications.py linguist-vendored=false
|
install/MarcMentat/MSC_modifications.py linguist-vendored=false
|
||||||
|
|
||||||
# ignore reference files for tests in language statistics
|
# ignore reference files for tests in language statistics
|
||||||
python/tests/reference/** linguist-vendored
|
python/tests/resources/** linguist-vendored
|
||||||
|
|
||||||
# ignore deprecated scripts
|
# ignore deprecated scripts
|
||||||
processing/legacy/** linguist-vendored
|
processing/legacy/** linguist-vendored
|
||||||
|
|
|
@ -2,7 +2,7 @@ name: Grid and Mesh Solver
|
||||||
on: [push]
|
on: [push]
|
||||||
|
|
||||||
env:
|
env:
|
||||||
PETSC_VERSION: '3.18.1'
|
PETSC_VERSION: '3.18.4'
|
||||||
HOMEBREW_NO_ANALYTICS: 'ON' # Make Homebrew installation a little quicker
|
HOMEBREW_NO_ANALYTICS: 'ON' # Make Homebrew installation a little quicker
|
||||||
HOMEBREW_NO_AUTO_UPDATE: 'ON'
|
HOMEBREW_NO_AUTO_UPDATE: 'ON'
|
||||||
HOMEBREW_NO_BOTTLE_SOURCE_FALLBACK: 'ON'
|
HOMEBREW_NO_BOTTLE_SOURCE_FALLBACK: 'ON'
|
||||||
|
@ -11,14 +11,14 @@ env:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
|
||||||
gcc:
|
gcc_ubuntu:
|
||||||
|
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ubuntu-22.04
|
||||||
|
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
os: [ubuntu-latest, macos-latest]
|
gcc_v: [9, 10, 11, 12]
|
||||||
gcc_v: [9, 10, 11] # Version of GCC compilers
|
fail-fast: false
|
||||||
|
|
||||||
env:
|
env:
|
||||||
GCC_V: ${{ matrix.gcc_v }}
|
GCC_V: ${{ matrix.gcc_v }}
|
||||||
|
@ -27,8 +27,7 @@ jobs:
|
||||||
|
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
- name: GCC - Install (Linux)
|
- name: GCC - Install
|
||||||
if: contains( matrix.os, 'ubuntu')
|
|
||||||
run: |
|
run: |
|
||||||
sudo add-apt-repository ppa:ubuntu-toolchain-r/test
|
sudo add-apt-repository ppa:ubuntu-toolchain-r/test
|
||||||
sudo apt-get update
|
sudo apt-get update
|
||||||
|
@ -38,12 +37,6 @@ jobs:
|
||||||
--slave /usr/bin/g++ g++ /usr/bin/g++-${GCC_V} \
|
--slave /usr/bin/g++ g++ /usr/bin/g++-${GCC_V} \
|
||||||
--slave /usr/bin/gcov gcov /usr/bin/gcov-${GCC_V}
|
--slave /usr/bin/gcov gcov /usr/bin/gcov-${GCC_V}
|
||||||
|
|
||||||
- name: GCC - Install (macOS)
|
|
||||||
if: contains( matrix.os, 'macos')
|
|
||||||
run: |
|
|
||||||
brew install gcc@${GCC_V} || brew upgrade gcc@${GCC_V} || true
|
|
||||||
brew link gcc@${GCC_V}
|
|
||||||
|
|
||||||
- name: PETSc - Cache download
|
- name: PETSc - Cache download
|
||||||
id: petsc-download
|
id: petsc-download
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v3
|
||||||
|
@ -63,28 +56,19 @@ jobs:
|
||||||
export PETSC_ARCH=gcc${GCC_V}
|
export PETSC_ARCH=gcc${GCC_V}
|
||||||
printenv >> $GITHUB_ENV
|
printenv >> $GITHUB_ENV
|
||||||
|
|
||||||
- name: PETSc - Cache installation
|
- name: PETSc - Cache Installation
|
||||||
id: petsc-install
|
id: petsc-install
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
path: petsc-${{ env.PETSC_VERSION }}
|
path: petsc-${{ env.PETSC_VERSION }}
|
||||||
key: petsc-${{ env.PETSC_VERSION }}-${{ matrix.os }}-gcc${{ matrix.gcc_v }}-${{ hashFiles('**/petscversion.h') }}
|
key: petsc-${{ env.PETSC_VERSION }}-gcc${{ matrix.gcc_v }}-${{ hashFiles('**/petscversion.h') }}
|
||||||
|
|
||||||
- name: PETSc - Install (Linux)
|
- name: PETSc - Installation
|
||||||
if: contains( matrix.os, 'ubuntu')
|
|
||||||
run: |
|
run: |
|
||||||
cd petsc-${PETSC_VERSION}
|
cd petsc-${PETSC_VERSION}
|
||||||
./configure --with-fc=gfortran --with-cc=gcc --with-cxx=g++ \
|
./configure --with-fc=gfortran --with-cc=gcc --with-cxx=g++ \
|
||||||
--download-mpich --download-fftw --download-hdf5 --download-hdf5-fortran-bindings=1 --download-zlib \
|
--download-openmpi --download-fftw --download-hdf5 --download-hdf5-fortran-bindings=1 --download-zlib \
|
||||||
--with-mpi-f90module-visibility=0
|
--with-mpi-f90module-visibility=1
|
||||||
make all
|
|
||||||
|
|
||||||
- name: PETSc - Install (macOS)
|
|
||||||
if: contains( matrix.os, 'macos')
|
|
||||||
run: |
|
|
||||||
cd petsc-${PETSC_VERSION}
|
|
||||||
./configure --with-fc=gfortran-${GCC_V} --with-cc=gcc-${GCC_V} --with-cxx=g++-${GCC_V} \
|
|
||||||
--download-openmpi --download-fftw --download-hdf5 --download-hdf5-fortran-bindings=1 --download-zlib
|
|
||||||
make all
|
make all
|
||||||
|
|
||||||
- name: DAMASK - Compile
|
- name: DAMASK - Compile
|
||||||
|
@ -99,6 +83,8 @@ jobs:
|
||||||
- name: DAMASK - Run
|
- name: DAMASK - Run
|
||||||
run: |
|
run: |
|
||||||
./bin/DAMASK_grid -l tensionX.yaml -g 20grains16x16x16.vti -w examples/grid
|
./bin/DAMASK_grid -l tensionX.yaml -g 20grains16x16x16.vti -w examples/grid
|
||||||
|
./bin/DAMASK_mesh -h
|
||||||
|
|
||||||
|
|
||||||
intel:
|
intel:
|
||||||
|
|
||||||
|
@ -107,6 +93,7 @@ jobs:
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
intel_v: [classic, llvm] # Variant of Intel compilers
|
intel_v: [classic, llvm] # Variant of Intel compilers
|
||||||
|
fail-fast: false
|
||||||
|
|
||||||
env:
|
env:
|
||||||
INTEL_V: ${{ matrix.intel_v }}
|
INTEL_V: ${{ matrix.intel_v }}
|
||||||
|
@ -143,7 +130,7 @@ jobs:
|
||||||
- name: PETSc - Prepare
|
- name: PETSc - Prepare
|
||||||
run: |
|
run: |
|
||||||
tar -xf download/petsc-${PETSC_VERSION}.tar.gz -C .
|
tar -xf download/petsc-${PETSC_VERSION}.tar.gz -C .
|
||||||
sed -i "1715s/if not os.path.isfile(os.path.join(self.packageDir,'configure')):/if True:/g" \
|
sed -i "1719s/if not os.path.isfile(os.path.join(self.packageDir,'configure')):/if True:/g" \
|
||||||
./petsc-${PETSC_VERSION}/config/BuildSystem/config/package.py
|
./petsc-${PETSC_VERSION}/config/BuildSystem/config/package.py
|
||||||
export PETSC_DIR=${PWD}/petsc-${PETSC_VERSION}
|
export PETSC_DIR=${PWD}/petsc-${PETSC_VERSION}
|
||||||
export PETSC_ARCH=intel-${INTEL_V}
|
export PETSC_ARCH=intel-${INTEL_V}
|
||||||
|
@ -179,6 +166,7 @@ jobs:
|
||||||
make all
|
make all
|
||||||
|
|
||||||
- name: DAMASK - Compile
|
- name: DAMASK - Compile
|
||||||
|
if: contains( matrix.intel_v, 'classic')
|
||||||
run: |
|
run: |
|
||||||
cmake -B build/grid -DDAMASK_SOLVER=grid -DCMAKE_INSTALL_PREFIX=${PWD}
|
cmake -B build/grid -DDAMASK_SOLVER=grid -DCMAKE_INSTALL_PREFIX=${PWD}
|
||||||
cmake --build build/grid --parallel
|
cmake --build build/grid --parallel
|
||||||
|
@ -187,6 +175,19 @@ jobs:
|
||||||
cmake --build build/mesh --parallel
|
cmake --build build/mesh --parallel
|
||||||
cmake --install build/mesh
|
cmake --install build/mesh
|
||||||
|
|
||||||
|
# ifx has issue with openMP
|
||||||
|
# https://community.intel.com/t5/Intel-Fortran-Compiler/ifx-ICE-and-SEGFAULT/m-p/1459877
|
||||||
|
- name: DAMASK - Compile
|
||||||
|
if: contains( matrix.intel_v, 'llvm')
|
||||||
|
run: |
|
||||||
|
cmake -B build/grid -DDAMASK_SOLVER=grid -DCMAKE_INSTALL_PREFIX=${PWD} -DOPENMP=OFF
|
||||||
|
cmake --build build/grid --parallel
|
||||||
|
cmake --install build/grid
|
||||||
|
cmake -B build/mesh -DDAMASK_SOLVER=mesh -DCMAKE_INSTALL_PREFIX=${PWD} -DOPENMP=OFF
|
||||||
|
cmake --build build/mesh --parallel
|
||||||
|
cmake --install build/mesh
|
||||||
|
|
||||||
- name: DAMASK - Run
|
- name: DAMASK - Run
|
||||||
run: |
|
run: |
|
||||||
./bin/DAMASK_grid -l tensionX.yaml -g 20grains16x16x16.vti -w examples/grid
|
./bin/DAMASK_grid -l tensionX.yaml -g 20grains16x16x16.vti -w examples/grid
|
||||||
|
./bin/DAMASK_mesh -h
|
||||||
|
|
|
@ -9,7 +9,7 @@ jobs:
|
||||||
|
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
python-version: ['3.8', '3.9', '3.10']
|
python-version: ['3.8', '3.9', '3.10', '3.11']
|
||||||
os: [ubuntu-latest, macos-latest, windows-latest]
|
os: [ubuntu-latest, macos-latest, windows-latest]
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
|
|
||||||
|
@ -75,7 +75,7 @@ jobs:
|
||||||
run: >
|
run: >
|
||||||
sudo apt-get update &&
|
sudo apt-get update &&
|
||||||
sudo apt-get remove mysql* &&
|
sudo apt-get remove mysql* &&
|
||||||
sudo apt-get install python3-pandas python3-scipy python3-h5py python3-vtk7 python3-matplotlib python3-yaml -y
|
sudo apt-get install python3-pandas python3-scipy python3-h5py python3-vtk9 python3-matplotlib python3-yaml -y
|
||||||
|
|
||||||
- name: Run unit tests
|
- name: Run unit tests
|
||||||
run: |
|
run: |
|
||||||
|
|
|
@ -181,13 +181,13 @@ open-source:
|
||||||
script:
|
script:
|
||||||
- module load ${COMPILER_INTEL} ${MPI_INTEL} ${PETSC_INTEL}
|
- module load ${COMPILER_INTEL} ${MPI_INTEL} ${PETSC_INTEL}
|
||||||
- cd PRIVATE/testing/pytest
|
- cd PRIVATE/testing/pytest
|
||||||
- pytest -k 'not compile and not Marc' --basetemp ${TESTROOT}/open-source -v
|
- pytest -k 'not compile and not Marc' -m 'not cifail' --basetemp ${TESTROOT}/open-source -v
|
||||||
|
|
||||||
Marc:
|
Marc:
|
||||||
stage: fortran
|
stage: fortran
|
||||||
script:
|
script:
|
||||||
- cd PRIVATE/testing/pytest
|
- cd PRIVATE/testing/pytest
|
||||||
- pytest -k 'not compile and Marc' --damask-root=${TESTROOT} --basetemp ${TESTROOT}/Marc -v
|
- pytest -k 'not compile and Marc' -m 'not cifail' --damask-root=${TESTROOT} --basetemp ${TESTROOT}/Marc -v
|
||||||
|
|
||||||
# Needs closer look
|
# Needs closer look
|
||||||
# Phenopowerlaw_singleSlip:
|
# Phenopowerlaw_singleSlip:
|
||||||
|
|
|
@ -11,7 +11,7 @@ endif()
|
||||||
project(Prerequisites LANGUAGES)
|
project(Prerequisites LANGUAGES)
|
||||||
set(ENV{PKG_CONFIG_PATH} "$ENV{PETSC_DIR}/$ENV{PETSC_ARCH}/lib/pkgconfig:$ENV{PKG_CONFIG_PATH}")
|
set(ENV{PKG_CONFIG_PATH} "$ENV{PETSC_DIR}/$ENV{PETSC_ARCH}/lib/pkgconfig:$ENV{PKG_CONFIG_PATH}")
|
||||||
pkg_check_modules(PETSC_MIN REQUIRED PETSc>=3.12.0 QUIET) #CMake does not support version range
|
pkg_check_modules(PETSC_MIN REQUIRED PETSc>=3.12.0 QUIET) #CMake does not support version range
|
||||||
pkg_check_modules(PETSC REQUIRED PETSc<3.19.0)
|
pkg_check_modules(PETSC REQUIRED PETSc<3.20.0)
|
||||||
|
|
||||||
pkg_get_variable(CMAKE_Fortran_COMPILER PETSc fcompiler)
|
pkg_get_variable(CMAKE_Fortran_COMPILER PETSc fcompiler)
|
||||||
pkg_get_variable(CMAKE_C_COMPILER PETSc ccompiler)
|
pkg_get_variable(CMAKE_C_COMPILER PETSc ccompiler)
|
||||||
|
@ -22,6 +22,8 @@ if(DAMASK_SOLVER STREQUAL "GRID")
|
||||||
project(damask-grid HOMEPAGE_URL https://damask.mpie.de LANGUAGES Fortran C)
|
project(damask-grid HOMEPAGE_URL https://damask.mpie.de LANGUAGES Fortran C)
|
||||||
elseif(DAMASK_SOLVER STREQUAL "MESH")
|
elseif(DAMASK_SOLVER STREQUAL "MESH")
|
||||||
project(damask-mesh HOMEPAGE_URL https://damask.mpie.de LANGUAGES Fortran C)
|
project(damask-mesh HOMEPAGE_URL https://damask.mpie.de LANGUAGES Fortran C)
|
||||||
|
elseif(DAMASK_SOLVER STREQUAL "TEST")
|
||||||
|
project(damask-test HOMEPAGE_URL https://damask.mpie.de LANGUAGES Fortran C)
|
||||||
else()
|
else()
|
||||||
message(FATAL_ERROR "Invalid solver: DAMASK_SOLVER=${DAMASK_SOLVER}")
|
message(FATAL_ERROR "Invalid solver: DAMASK_SOLVER=${DAMASK_SOLVER}")
|
||||||
endif()
|
endif()
|
||||||
|
@ -90,14 +92,21 @@ endif()
|
||||||
|
|
||||||
|
|
||||||
list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake)
|
list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake)
|
||||||
if (CMAKE_Fortran_COMPILER_ID STREQUAL "Intel")
|
if (CMAKE_Fortran_COMPILER_ID STREQUAL "GNU")
|
||||||
include(Compiler-Intel)
|
|
||||||
elseif(CMAKE_Fortran_COMPILER_ID STREQUAL "GNU")
|
|
||||||
include(Compiler-GNU)
|
include(Compiler-GNU)
|
||||||
|
set(Fortran_COMPILER_VERSION_MIN 9.1)
|
||||||
|
elseif(CMAKE_Fortran_COMPILER_ID STREQUAL "Intel")
|
||||||
|
include(Compiler-Intel)
|
||||||
|
set(Fortran_COMPILER_VERSION_MIN 19)
|
||||||
elseif(CMAKE_Fortran_COMPILER_ID STREQUAL "IntelLLVM")
|
elseif(CMAKE_Fortran_COMPILER_ID STREQUAL "IntelLLVM")
|
||||||
include(Compiler-IntelLLVM)
|
include(Compiler-IntelLLVM)
|
||||||
|
set(Fortran_COMPILER_VERSION_MIN 19)
|
||||||
else()
|
else()
|
||||||
message(FATAL_ERROR "Compiler type(CMAKE_Fortran_COMPILER_ID) not recognized")
|
message(FATAL_ERROR "Compiler '${CMAKE_Fortran_COMPILER_ID}' not supported")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(CMAKE_Fortran_COMPILER_VERSION VERSION_LESS Fortran_COMPILER_VERSION_MIN)
|
||||||
|
message(FATAL_ERROR "Version '${CMAKE_Fortran_COMPILER_VERSION}' of '${CMAKE_Fortran_COMPILER_ID}' is not supported")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
file(STRINGS "$ENV{PETSC_DIR}/$ENV{PETSC_ARCH}/lib/petsc/conf/petscvariables" PETSC_EXTERNAL_LIB REGEX "PETSC_EXTERNAL_LIB_BASIC = .*$?")
|
file(STRINGS "$ENV{PETSC_DIR}/$ENV{PETSC_ARCH}/lib/petsc/conf/petscvariables" PETSC_EXTERNAL_LIB REGEX "PETSC_EXTERNAL_LIB_BASIC = .*$?")
|
||||||
|
|
5
Makefile
5
Makefile
|
@ -17,6 +17,11 @@ mesh:
|
||||||
@cmake -B build/mesh -DDAMASK_SOLVER=mesh -DCMAKE_INSTALL_PREFIX=${PWD} -DCMAKE_BUILD_TYPE=${BUILD_TYPE} -DBUILDCMD_POST=${BUILDCMD_POST} -DBUILDCMD_PRE=${BUILDCMD_PRE} -DOPTIMIZATION=${OPTIMIZATION} -DOPENMP=${OPENMP}
|
@cmake -B build/mesh -DDAMASK_SOLVER=mesh -DCMAKE_INSTALL_PREFIX=${PWD} -DCMAKE_BUILD_TYPE=${BUILD_TYPE} -DBUILDCMD_POST=${BUILDCMD_POST} -DBUILDCMD_PRE=${BUILDCMD_PRE} -DOPTIMIZATION=${OPTIMIZATION} -DOPENMP=${OPENMP}
|
||||||
@cmake --build build/mesh --parallel --target install
|
@cmake --build build/mesh --parallel --target install
|
||||||
|
|
||||||
|
.PHONY: test
|
||||||
|
test:
|
||||||
|
@cmake -B build/test -DDAMASK_SOLVER=test -DCMAKE_INSTALL_PREFIX=${PWD} -DCMAKE_BUILD_TYPE=${BUILD_TYPE} -DBUILDCMD_POST=${BUILDCMD_POST} -DBUILDCMD_PRE=${BUILDCMD_PRE} -DOPTIMIZATION=${OPTIMIZATION} -DOPENMP=${OPENMP}
|
||||||
|
@cmake --build build/test --parallel --target install
|
||||||
|
|
||||||
.PHONY: clean
|
.PHONY: clean
|
||||||
clean:
|
clean:
|
||||||
@rm -rf build
|
@rm -rf build
|
||||||
|
|
2
PRIVATE
2
PRIVATE
|
@ -1 +1 @@
|
||||||
Subproject commit 547bfe56d67cba358a7bb9582f2f7c0e344befd8
|
Subproject commit 22a23a9d5939d49d9d277c7066d9b68003a33324
|
|
@ -93,8 +93,6 @@ set (DEBUG_FLAGS "${DEBUG_FLAGS},pointers")
|
||||||
# ... for certain disassociated or uninitialized pointers or unallocated allocatable objects.
|
# ... for certain disassociated or uninitialized pointers or unallocated allocatable objects.
|
||||||
set (DEBUG_FLAGS "${DEBUG_FLAGS},uninit")
|
set (DEBUG_FLAGS "${DEBUG_FLAGS},uninit")
|
||||||
# ... for uninitialized variables.
|
# ... for uninitialized variables.
|
||||||
set (DEBUG_FLAGS "${DEBUG_FLAGS} -ftrapuv")
|
|
||||||
# ... initializes stack local variables to an unusual value to aid error detection
|
|
||||||
set (DEBUG_FLAGS "${DEBUG_FLAGS} -fpe-all=0 -ftz")
|
set (DEBUG_FLAGS "${DEBUG_FLAGS} -fpe-all=0 -ftz")
|
||||||
# ... capture all floating-point exceptions, need to overwrite -no-ftz
|
# ... capture all floating-point exceptions, need to overwrite -no-ftz
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ if (CMAKE_Fortran_COMPILER_VERSION VERSION_LESS 18.0)
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
if (OPENMP)
|
if (OPENMP)
|
||||||
set (OPENMP_FLAGS "-qopenmp")
|
set (OPENMP_FLAGS "-fiopenmp")
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
if (OPTIMIZATION STREQUAL "OFF" OR OPTIMIZATION STREQUAL "DEBUG")
|
if (OPTIMIZATION STREQUAL "OFF" OR OPTIMIZATION STREQUAL "DEBUG")
|
||||||
|
@ -23,6 +23,8 @@ endif ()
|
||||||
set (STANDARD_CHECK "-stand f18 -assume nostd_mod_proc_name")
|
set (STANDARD_CHECK "-stand f18 -assume nostd_mod_proc_name")
|
||||||
set (LINKER_FLAGS "${LINKER_FLAGS} -shared-intel")
|
set (LINKER_FLAGS "${LINKER_FLAGS} -shared-intel")
|
||||||
# Link against shared Intel libraries instead of static ones
|
# Link against shared Intel libraries instead of static ones
|
||||||
|
set (LINKER_FLAGS "${LINKER_FLAGS} -shared-intel -fc=ifx")
|
||||||
|
# enforce use of ifx for MPI wrapper
|
||||||
|
|
||||||
#------------------------------------------------------------------------------------------------
|
#------------------------------------------------------------------------------------------------
|
||||||
# Fine tuning compilation options
|
# Fine tuning compilation options
|
||||||
|
@ -93,8 +95,6 @@ set (DEBUG_FLAGS "${DEBUG_FLAGS},pointers")
|
||||||
# ... for certain disassociated or uninitialized pointers or unallocated allocatable objects.
|
# ... for certain disassociated or uninitialized pointers or unallocated allocatable objects.
|
||||||
set (DEBUG_FLAGS "${DEBUG_FLAGS},uninit")
|
set (DEBUG_FLAGS "${DEBUG_FLAGS},uninit")
|
||||||
# ... for uninitialized variables.
|
# ... for uninitialized variables.
|
||||||
set (DEBUG_FLAGS "${DEBUG_FLAGS} -ftrapuv")
|
|
||||||
# ... initializes stack local variables to an unusual value to aid error detection
|
|
||||||
set (DEBUG_FLAGS "${DEBUG_FLAGS} -fpe-all=0 -ftz")
|
set (DEBUG_FLAGS "${DEBUG_FLAGS} -fpe-all=0 -ftz")
|
||||||
# ... capture all floating-point exceptions, need to overwrite -no-ftz
|
# ... capture all floating-point exceptions, need to overwrite -no-ftz
|
||||||
|
|
||||||
|
|
|
@ -1,12 +0,0 @@
|
||||||
phase: [basic, extensive, selective]
|
|
||||||
materialpoint: [basic, extensive, selective]
|
|
||||||
|
|
||||||
# options for selective debugging
|
|
||||||
element: 1
|
|
||||||
integrationpoint: 1
|
|
||||||
constituent: 1
|
|
||||||
|
|
||||||
# solver-specific
|
|
||||||
mesh: [PETSc]
|
|
||||||
grid: [basic, rotation, PETSc]
|
|
||||||
Marc: [basic]
|
|
|
@ -6,8 +6,8 @@ N_cl: [3]
|
||||||
|
|
||||||
g_crit: [0.5e+7]
|
g_crit: [0.5e+7]
|
||||||
s_crit: [0.006666]
|
s_crit: [0.006666]
|
||||||
dot_o: 1.e-3
|
dot_o_0: 1.e-3
|
||||||
q: 20
|
p: 20
|
||||||
|
|
||||||
l_c: 1.0
|
l_c: 1.0
|
||||||
mu: 0.001
|
mu: 0.001
|
||||||
|
|
|
@ -3,7 +3,7 @@ type: Hooke
|
||||||
references:
|
references:
|
||||||
- D.J. Dever,
|
- D.J. Dever,
|
||||||
Journal of Applied Physics 43(8):3293-3301, 1972,
|
Journal of Applied Physics 43(8):3293-3301, 1972,
|
||||||
https://doi.org/10.1063/1.1661710
|
https://doi.org/10.1063/1.1661710,
|
||||||
fit to Tab. II (T_min=25ºC, T_max=880ºC)
|
fit to Tab. II (T_min=25ºC, T_max=880ºC)
|
||||||
|
|
||||||
C_11: 232.2e+9
|
C_11: 232.2e+9
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
type: Hooke
|
type: Hooke
|
||||||
|
|
||||||
references:
|
references:
|
||||||
- Wang et al.,
|
- Z. Wang et al.,
|
||||||
Materials Science and Engineering:A 674:406-412, 2016,
|
Materials Science and Engineering:A 674:406-412, 2016,
|
||||||
https://doi.org/10.1016/j.msea.2016.08.010,
|
https://doi.org/10.1016/j.msea.2016.08.010,
|
||||||
fit to Tab. 2 (last 3 rows)
|
fit to Tab. 2 (last 3 rows)
|
||||||
|
|
|
@ -3,8 +3,9 @@ type: Hooke
|
||||||
references:
|
references:
|
||||||
- S.A. Kim and W.L. Johnson,
|
- S.A. Kim and W.L. Johnson,
|
||||||
Materials Science & Engineering A 452-453:633-639, 2007,
|
Materials Science & Engineering A 452-453:633-639, 2007,
|
||||||
https://doi.org/10.1016/j.msea.2006.11.147
|
https://doi.org/10.1016/j.msea.2006.11.147,
|
||||||
|
Tab. 1 (averaged for bcc)
|
||||||
|
|
||||||
C_11: 268.1e+9
|
C_11: 267.9e+9
|
||||||
C_12: 111.2e+9
|
C_12: 110.8e+9
|
||||||
C_44: 79.06e+9
|
C_44: 78.9e+9
|
||||||
|
|
|
@ -3,7 +3,7 @@ type: dislotungsten
|
||||||
references:
|
references:
|
||||||
- D. Cereceda et al.,
|
- D. Cereceda et al.,
|
||||||
International Journal of Plasticity 78:242-265, 2016,
|
International Journal of Plasticity 78:242-265, 2016,
|
||||||
http://dx.doi.org/10.1016/j.ijplas.2015.09.002
|
https://doi.org/10.1016/j.ijplas.2015.09.002
|
||||||
- R. Gröger et al.,
|
- R. Gröger et al.,
|
||||||
Acta Materialia 56(19):5412-5425, 2008,
|
Acta Materialia 56(19):5412-5425, 2008,
|
||||||
https://doi.org/10.1016/j.actamat.2008.07.037
|
https://doi.org/10.1016/j.actamat.2008.07.037
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
type: kinehardening
|
||||||
|
|
||||||
|
references:
|
||||||
|
- J.A. Wollmershauser et al.,
|
||||||
|
International Journal of Fatigue 36(1):181-193, 2012,
|
||||||
|
https://doi.org/10.1016/j.ijfatigue.2011.07.008
|
||||||
|
|
||||||
|
output: [xi, chi, chi_flip, gamma_flip, gamma, sgn(gamma)]
|
||||||
|
|
||||||
|
N_sl: [12]
|
||||||
|
|
||||||
|
xi_0: [0.070e+9] # τ_0,for
|
||||||
|
xi_inf: [0.015e+9] # τ_1,for
|
||||||
|
h_0_xi: [0.065e+9] # θ_0,for
|
||||||
|
h_inf_xi: [0.045e+9] # θ_1,for
|
||||||
|
|
||||||
|
chi_inf: [0.027e+9] # τ_1,bs
|
||||||
|
h_0_chi: [55e+9] # θ_0,bs
|
||||||
|
h_inf_chi: [1.3e+9] # θ_1,bs
|
||||||
|
|
||||||
|
n: 20 # not mentioned in the reference
|
||||||
|
dot_gamma_0: 1e-4 # not mentioned in the reference
|
||||||
|
h_sl-sl: [1, 1, 1, 1, 1, 1, 1]
|
|
@ -0,0 +1,19 @@
|
||||||
|
type: phenopowerlaw
|
||||||
|
|
||||||
|
references:
|
||||||
|
- T.J. Barrett and M. Knezevic,
|
||||||
|
Computer Methods in Applied Mechanics and Engineering 354:245-270, 2019,
|
||||||
|
https://doi.org/10.1016/j.cma.2019.05.035,
|
||||||
|
fitted to data shown in Fig 1 and Fig. 2a
|
||||||
|
|
||||||
|
output: [xi_sl, gamma_sl]
|
||||||
|
|
||||||
|
N_sl: [12]
|
||||||
|
|
||||||
|
n_sl: 20
|
||||||
|
a_sl: 3.7
|
||||||
|
h_0_sl-sl: 1.02e+9
|
||||||
|
xi_0_sl: [76.e+6]
|
||||||
|
xi_inf_sl: [266.e+6]
|
||||||
|
h_sl-sl: [1, 1, 5.123, 0.574, 1.123, 1.123, 1]
|
||||||
|
dot_gamma_0_sl: 0.001
|
|
@ -4,19 +4,16 @@ references:
|
||||||
- W.F. Hosford et al.,
|
- W.F. Hosford et al.,
|
||||||
Acta Metallurgica 8(3):187-199, 1960,
|
Acta Metallurgica 8(3):187-199, 1960,
|
||||||
https://doi.org/10.1016/0001-6160(60)90127-9,
|
https://doi.org/10.1016/0001-6160(60)90127-9,
|
||||||
fitted from Fig. 5
|
fitted to Fig. 5 ([111] and [001])
|
||||||
- U.F. Kocks,
|
|
||||||
Metallurgical and Materials Transactions B 1:1121–1143, 1970,
|
|
||||||
https://doi.org/10.1007/BF02900224
|
|
||||||
|
|
||||||
output: [xi_sl, gamma_sl]
|
output: [xi_sl, gamma_sl]
|
||||||
|
|
||||||
N_sl: [12]
|
N_sl: [12]
|
||||||
|
|
||||||
n_sl: 20
|
n_sl: 20
|
||||||
a_sl: 3.1
|
a_sl: 5.4
|
||||||
h_0_sl-sl: 1.7e+8
|
h_0_sl-sl: 281.5e+6
|
||||||
xi_0_sl: [5.0e+6]
|
xi_0_sl: [2.69e+6]
|
||||||
xi_inf_sl: [37.5e+6]
|
xi_inf_sl: [67.5e+6]
|
||||||
h_sl-sl: [1, 1, 1.4, 1.4, 1.4, 1.4, 1.4]
|
h_sl-sl: [1, 1, 5.123, 0.574, 1.123, 1.123, 1]
|
||||||
dot_gamma_0_sl: 7.5e-5
|
dot_gamma_0_sl: 7.5e-5
|
||||||
|
|
|
@ -1,22 +1,19 @@
|
||||||
type: phenopowerlaw
|
type: phenopowerlaw
|
||||||
|
|
||||||
references:
|
references:
|
||||||
- T Takeuchi,
|
- T. Takeuchi,
|
||||||
Transactions of the Japan Institute of Metals 16(10):629-640, 1975,
|
Transactions of the Japan Institute of Metals 16(10):629-640, 1975,
|
||||||
https://doi.org/10.2320/matertrans1960.16.629,
|
https://doi.org/10.2320/matertrans1960.16.629,
|
||||||
fitted from Fig. 3b
|
fitted to Fig. 3b ([111] and [001])
|
||||||
- U.F. Kocks,
|
|
||||||
Metallurgical and Materials Transactions B 1:1121–1143, 1970,
|
|
||||||
https://doi.org/10.1007/BF02900224
|
|
||||||
|
|
||||||
output: [xi_sl, gamma_sl]
|
output: [xi_sl, gamma_sl]
|
||||||
|
|
||||||
N_sl: [12]
|
N_sl: [12]
|
||||||
|
|
||||||
n_sl: 20
|
n_sl: 20
|
||||||
a_sl: 1.0
|
a_sl: 0.6
|
||||||
h_0_sl-sl: 2.4e+8
|
h_0_sl-sl: 3.5e+8
|
||||||
xi_0_sl: [1.5e+6]
|
xi_0_sl: [1.6e+6]
|
||||||
xi_inf_sl: [112.5e+6]
|
xi_inf_sl: [96.4e+6]
|
||||||
h_sl-sl: [1, 1, 1.4, 1.4, 1.4, 1.4, 1.4]
|
h_sl-sl: [1, 1, 5.123, 0.574, 1.123, 1.123, 1]
|
||||||
dot_gamma_0_sl: 3.e-3
|
dot_gamma_0_sl: 3.e-3
|
||||||
|
|
|
@ -4,17 +4,16 @@ references:
|
||||||
- K.M. Jackson and C. Lang,
|
- K.M. Jackson and C. Lang,
|
||||||
Platinum Metals Review 50:15-19, 2006,
|
Platinum Metals Review 50:15-19, 2006,
|
||||||
https://doi.org/10.1595/147106705X93359,
|
https://doi.org/10.1595/147106705X93359,
|
||||||
fitted from Fig. 5 (Pt-5% Cu recrystallised)
|
fitted to Fig. 5 (Pt-5% Cu recrystallised)
|
||||||
- U.F. Kocks,
|
|
||||||
Metallurgical and Materials Transactions B 1:1121–1143, 1970,
|
output: [xi_sl, gamma_sl]
|
||||||
https://doi.org/10.1007/BF02900224
|
|
||||||
|
|
||||||
N_sl: [12]
|
N_sl: [12]
|
||||||
|
|
||||||
n_sl: 1.6
|
n_sl: 20
|
||||||
a_sl: 0.8
|
a_sl: 0.9
|
||||||
h_0_sl-sl: 300.0e+6
|
h_0_sl-sl: 781.2e+6
|
||||||
xi_0_sl: [150.0e+6]
|
xi_0_sl: [114.e+6]
|
||||||
xi_inf_sl: [500.0e+6]
|
xi_inf_sl: [207.e+6]
|
||||||
h_sl-sl: [1, 1, 1.4, 1.4, 1.4, 1.4, 1.4]
|
h_sl-sl: [1, 1, 5.123, 0.574, 1.123, 1.123, 1]
|
||||||
dot_gamma_0_sl: 0.0001
|
dot_gamma_0_sl: 0.001
|
||||||
|
|
|
@ -25,5 +25,6 @@ from ._colormap import Colormap # noqa
|
||||||
from ._vtk import VTK # noqa
|
from ._vtk import VTK # noqa
|
||||||
from ._config import Config # noqa
|
from ._config import Config # noqa
|
||||||
from ._configmaterial import ConfigMaterial # noqa
|
from ._configmaterial import ConfigMaterial # noqa
|
||||||
|
from ._loadcasegrid import LoadcaseGrid # noqa
|
||||||
from ._grid import Grid # noqa
|
from ._grid import Grid # noqa
|
||||||
from ._result import Result # noqa
|
from ._result import Result # noqa
|
||||||
|
|
|
@ -28,10 +28,10 @@ _REF_WHITE = np.array([.95047, 1.00000, 1.08883])
|
||||||
|
|
||||||
class Colormap(mpl.colors.ListedColormap):
|
class Colormap(mpl.colors.ListedColormap):
|
||||||
"""
|
"""
|
||||||
Enhance matplotlib colormap functionality to be used within DAMASK.
|
Enhance matplotlib colormap functionality for use within DAMASK.
|
||||||
|
|
||||||
Colors are internally stored as R(ed) G(green) B(lue) values.
|
Colors are internally stored as R(ed) G(green) B(lue) values.
|
||||||
The colormap can be used in matplotlib, seaborn, etc., or can
|
A colormap can be used in matplotlib, seaborn, etc., or can be
|
||||||
exported to file for external use.
|
exported to file for external use.
|
||||||
|
|
||||||
References
|
References
|
||||||
|
@ -153,12 +153,12 @@ class Colormap(mpl.colors.ListedColormap):
|
||||||
- 'hsl': Hue Saturation Luminance.
|
- 'hsl': Hue Saturation Luminance.
|
||||||
- 'xyz': CIE Xyz.
|
- 'xyz': CIE Xyz.
|
||||||
- 'lab': CIE Lab.
|
- 'lab': CIE Lab.
|
||||||
- 'msh': Msh (for perceptual uniform interpolation).
|
- 'msh': Msh (for perceptually uniform interpolation).
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
-------
|
-------
|
||||||
new : damask.Colormap
|
new : damask.Colormap
|
||||||
Colormap within given bounds.
|
Colormap spanning given bounds.
|
||||||
|
|
||||||
Examples
|
Examples
|
||||||
--------
|
--------
|
||||||
|
@ -276,7 +276,7 @@ class Colormap(mpl.colors.ListedColormap):
|
||||||
def shade(self,
|
def shade(self,
|
||||||
field: np.ndarray,
|
field: np.ndarray,
|
||||||
bounds: Optional[FloatSequence] = None,
|
bounds: Optional[FloatSequence] = None,
|
||||||
gap: Optional[float] = None) -> Image:
|
gap: Optional[float] = None) -> Image.Image:
|
||||||
"""
|
"""
|
||||||
Generate PIL image of 2D field using colormap.
|
Generate PIL image of 2D field using colormap.
|
||||||
|
|
||||||
|
@ -288,6 +288,7 @@ class Colormap(mpl.colors.ListedColormap):
|
||||||
Value range (left,right) spanned by colormap.
|
Value range (left,right) spanned by colormap.
|
||||||
gap : field.dtype, optional
|
gap : field.dtype, optional
|
||||||
Transparent value. NaN will always be rendered transparent.
|
Transparent value. NaN will always be rendered transparent.
|
||||||
|
Defaults to None.
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
-------
|
-------
|
||||||
|
@ -334,6 +335,7 @@ class Colormap(mpl.colors.ListedColormap):
|
||||||
--------
|
--------
|
||||||
>>> import damask
|
>>> import damask
|
||||||
>>> damask.Colormap.from_predefined('stress').reversed()
|
>>> damask.Colormap.from_predefined('stress').reversed()
|
||||||
|
Colormap: stress_r
|
||||||
|
|
||||||
"""
|
"""
|
||||||
rev = super().reversed(name)
|
rev = super().reversed(name)
|
||||||
|
@ -353,6 +355,7 @@ class Colormap(mpl.colors.ListedColormap):
|
||||||
If None, colormap name + suffix.
|
If None, colormap name + suffix.
|
||||||
suffix: str, optional
|
suffix: str, optional
|
||||||
Extension to use for colormap file.
|
Extension to use for colormap file.
|
||||||
|
Defaults to empty.
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
-------
|
-------
|
||||||
|
@ -452,8 +455,8 @@ class Colormap(mpl.colors.ListedColormap):
|
||||||
|
|
||||||
References
|
References
|
||||||
----------
|
----------
|
||||||
https://www.kennethmoreland.com/color-maps/ColorMapsExpanded.pdf
|
| https://www.kennethmoreland.com/color-maps/ColorMapsExpanded.pdf
|
||||||
https://www.kennethmoreland.com/color-maps/diverging_map.py
|
| https://www.kennethmoreland.com/color-maps/diverging_map.py
|
||||||
|
|
||||||
"""
|
"""
|
||||||
def rad_diff(a,b):
|
def rad_diff(a,b):
|
||||||
|
@ -735,8 +738,8 @@ class Colormap(mpl.colors.ListedColormap):
|
||||||
|
|
||||||
References
|
References
|
||||||
----------
|
----------
|
||||||
https://www.kennethmoreland.com/color-maps/ColorMapsExpanded.pdf
|
| https://www.kennethmoreland.com/color-maps/ColorMapsExpanded.pdf
|
||||||
https://www.kennethmoreland.com/color-maps/diverging_map.py
|
| https://www.kennethmoreland.com/color-maps/diverging_map.py
|
||||||
|
|
||||||
"""
|
"""
|
||||||
M = np.linalg.norm(lab)
|
M = np.linalg.norm(lab)
|
||||||
|
@ -763,8 +766,8 @@ class Colormap(mpl.colors.ListedColormap):
|
||||||
|
|
||||||
References
|
References
|
||||||
----------
|
----------
|
||||||
https://www.kennethmoreland.com/color-maps/ColorMapsExpanded.pdf
|
| https://www.kennethmoreland.com/color-maps/ColorMapsExpanded.pdf
|
||||||
https://www.kennethmoreland.com/color-maps/diverging_map.py
|
| https://www.kennethmoreland.com/color-maps/diverging_map.py
|
||||||
|
|
||||||
"""
|
"""
|
||||||
return np.array([
|
return np.array([
|
||||||
|
|
|
@ -2,6 +2,7 @@ import copy
|
||||||
from io import StringIO
|
from io import StringIO
|
||||||
from collections.abc import Iterable
|
from collections.abc import Iterable
|
||||||
import abc
|
import abc
|
||||||
|
import platform
|
||||||
from typing import Optional, Union, Dict, Any, Type, TypeVar
|
from typing import Optional, Union, Dict, Any, Type, TypeVar
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
@ -43,7 +44,7 @@ class NiceDumper(SafeDumper):
|
||||||
return self.represent_data(data.tolist())
|
return self.represent_data(data.tolist())
|
||||||
if isinstance(data, Rotation):
|
if isinstance(data, Rotation):
|
||||||
return self.represent_data(data.quaternion.tolist())
|
return self.represent_data(data.quaternion.tolist())
|
||||||
if hasattr(data, 'dtype'):
|
if isinstance(data, np.generic):
|
||||||
return self.represent_data(data.item())
|
return self.represent_data(data.item())
|
||||||
|
|
||||||
return super().represent_data(data)
|
return super().represent_data(data)
|
||||||
|
@ -57,15 +58,42 @@ class Config(dict):
|
||||||
"""YAML-based configuration."""
|
"""YAML-based configuration."""
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
yml: Union[None, str, Dict[str, Any]] = None,
|
config: Optional[Union[str, Dict[str, Any]]] = None,
|
||||||
**kwargs):
|
**kwargs):
|
||||||
"""Initialize from YAML, dict, or key=value pairs."""
|
"""
|
||||||
if isinstance(yml,str):
|
New YAML-based configuration.
|
||||||
kwargs.update(yaml.load(yml, Loader=SafeLoader))
|
|
||||||
elif isinstance(yml,dict):
|
Parameters
|
||||||
kwargs.update(yml)
|
----------
|
||||||
|
config : dict or str, optional
|
||||||
|
Configuration. String needs to be valid YAML.
|
||||||
|
**kwargs: arbitray keyword-value pairs, optional
|
||||||
|
Top level entries of the configuration.
|
||||||
|
|
||||||
|
Notes
|
||||||
|
-----
|
||||||
|
Values given as keyword-value pairs take precedence
|
||||||
|
over entries with the same keyword in 'config'.
|
||||||
|
|
||||||
|
"""
|
||||||
|
if int(platform.python_version_tuple()[1]) >= 9:
|
||||||
|
if isinstance(config,str):
|
||||||
|
kwargs = yaml.load(config, Loader=SafeLoader) | kwargs
|
||||||
|
elif isinstance(config,dict):
|
||||||
|
kwargs = config | kwargs # type: ignore
|
||||||
|
|
||||||
|
super().__init__(**kwargs)
|
||||||
|
else:
|
||||||
|
if isinstance(config,str):
|
||||||
|
c = yaml.load(config, Loader=SafeLoader)
|
||||||
|
elif isinstance(config,dict):
|
||||||
|
c = config.copy()
|
||||||
|
else:
|
||||||
|
c = {}
|
||||||
|
c.update(kwargs)
|
||||||
|
|
||||||
|
super().__init__(**c)
|
||||||
|
|
||||||
super().__init__(**kwargs)
|
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -1,12 +1,14 @@
|
||||||
|
from typing import Optional, Union, Sequence, Dict, Any, List
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import h5py
|
import h5py
|
||||||
from typing import Optional, Union, Sequence, Dict, Any, Collection
|
|
||||||
|
|
||||||
from ._typehints import FileHandle
|
from ._typehints import FileHandle, FloatSequence, StrSequence
|
||||||
from . import Config
|
from . import Config
|
||||||
from . import Rotation
|
from . import Rotation
|
||||||
from . import Orientation
|
from . import Orientation
|
||||||
from . import util
|
from . import util
|
||||||
|
from . import tensor
|
||||||
from . import Table
|
from . import Table
|
||||||
|
|
||||||
|
|
||||||
|
@ -22,33 +24,43 @@ class ConfigMaterial(Config):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
d: Optional[Dict[str, Any]] = None,
|
config: Optional[Union[str,Dict[str,Any]]] = None,*,
|
||||||
**kwargs):
|
homogenization: Optional[Dict[str,Dict]] = None,
|
||||||
|
phase: Optional[Dict[str,Dict]] = None,
|
||||||
|
material: Optional[List[Dict[str,Any]]] = None):
|
||||||
"""
|
"""
|
||||||
New material configuration.
|
New material configuration.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
d : dictionary or YAML string, optional
|
config : dict or str, optional
|
||||||
Initial content. Defaults to None, in which case empty entries for
|
Material configuration. String needs to be valid YAML.
|
||||||
any missing material, homogenization, and phase entry are created.
|
homogenization : dict, optional
|
||||||
kwargs : key=value pairs, optional
|
Homogenization configuration.
|
||||||
Initial content specified as pairs of key=value.
|
Defaults to an empty dict if 'config' is not given.
|
||||||
|
phase : dict, optional
|
||||||
|
Phase configuration.
|
||||||
|
Defaults to an empty dict if 'config' is not given.
|
||||||
|
material : dict, optional
|
||||||
|
Materialpoint configuration.
|
||||||
|
Defaults to an empty list if 'config' is not given.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
default: Collection
|
kwargs: Dict[str,Union[Dict[str,Dict],List[Dict[str,Any]]]] = {}
|
||||||
if d is None:
|
for arg,value in zip(['homogenization','phase','material'],[homogenization,phase,material]):
|
||||||
for section, default in {'material':[],'homogenization':{},'phase':{}}.items():
|
if value is None and config is None:
|
||||||
if section not in kwargs: kwargs.update({section:default})
|
kwargs[arg] = [] if arg == 'material' else {}
|
||||||
|
elif value is not None:
|
||||||
|
kwargs[arg] = value
|
||||||
|
|
||||||
super().__init__(d,**kwargs)
|
super().__init__(config,**kwargs)
|
||||||
|
|
||||||
|
|
||||||
def save(self,
|
def save(self,
|
||||||
fname: FileHandle = 'material.yaml',
|
fname: FileHandle = 'material.yaml',
|
||||||
**kwargs):
|
**kwargs):
|
||||||
"""
|
"""
|
||||||
Save to yaml file.
|
Save to YAML file.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
|
@ -65,7 +77,7 @@ class ConfigMaterial(Config):
|
||||||
def load(cls,
|
def load(cls,
|
||||||
fname: FileHandle = 'material.yaml') -> 'ConfigMaterial':
|
fname: FileHandle = 'material.yaml') -> 'ConfigMaterial':
|
||||||
"""
|
"""
|
||||||
Load from yaml file.
|
Load from YAML file.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
|
@ -168,8 +180,12 @@ class ConfigMaterial(Config):
|
||||||
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def from_table(table: Table,
|
def from_table(table: Table,*,
|
||||||
**kwargs) -> 'ConfigMaterial':
|
homogenization: Optional[Union[str,StrSequence]] = None,
|
||||||
|
phase: Optional[Union[str,StrSequence]] = None,
|
||||||
|
v: Optional[Union[str,FloatSequence]] = None,
|
||||||
|
O: Optional[Union[str,FloatSequence]] = None,
|
||||||
|
V_e: Optional[Union[str,FloatSequence]] = None) -> 'ConfigMaterial':
|
||||||
"""
|
"""
|
||||||
Generate from an ASCII table.
|
Generate from an ASCII table.
|
||||||
|
|
||||||
|
@ -177,16 +193,33 @@ class ConfigMaterial(Config):
|
||||||
----------
|
----------
|
||||||
table : damask.Table
|
table : damask.Table
|
||||||
Table that contains material information.
|
Table that contains material information.
|
||||||
**kwargs
|
homogenization: (array-like) of str, optional
|
||||||
Keyword arguments where the key is the property name and
|
Homogenization label.
|
||||||
the value specifies either the label of the data column in the table
|
phase: (array-like) of str, optional
|
||||||
or a constant value.
|
Phase label (per constituent).
|
||||||
|
v: (array-like) of float or str, optional
|
||||||
|
Constituent volume fraction (per constituent).
|
||||||
|
Defaults to 1/N_constituent.
|
||||||
|
O: (array-like) of damask.Rotation or np.array/list of shape(4) or str, optional
|
||||||
|
Orientation as unit quaternion (per constituent).
|
||||||
|
V_e: (array-like) of np.array/list of shape(3,3) or str, optional
|
||||||
|
Left elastic stretch (per constituent).
|
||||||
|
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
-------
|
-------
|
||||||
new : damask.ConfigMaterial
|
new : damask.ConfigMaterial
|
||||||
Material configuration from values in table.
|
Material configuration from values in table.
|
||||||
|
|
||||||
|
Notes
|
||||||
|
-----
|
||||||
|
If the value of an argument is a string that is a column label,
|
||||||
|
data from the table is used to fill the corresponding entry in
|
||||||
|
the material configuration. Otherwise, the value is used directly.
|
||||||
|
|
||||||
|
First index of array-like values that are defined per constituent
|
||||||
|
runs over materials, whereas second index runs over constituents.
|
||||||
|
|
||||||
Examples
|
Examples
|
||||||
--------
|
--------
|
||||||
>>> import damask
|
>>> import damask
|
||||||
|
@ -228,15 +261,16 @@ class ConfigMaterial(Config):
|
||||||
phase: {Aluminum: null, Steel: null}
|
phase: {Aluminum: null, Steel: null}
|
||||||
|
|
||||||
"""
|
"""
|
||||||
kwargs_ = {k:table.get(v) if v in table.labels else np.atleast_2d([v]*len(table)).T for k,v in kwargs.items()}
|
kwargs = {}
|
||||||
|
for arg,val in zip(['homogenization','phase','v','O','V_e'],[homogenization,phase,v,O,V_e]):
|
||||||
|
if val is not None:
|
||||||
|
kwargs[arg] = table.get(val) if val in table.labels else np.atleast_2d([val]*len(table)).T # type: ignore
|
||||||
|
|
||||||
_,idx = np.unique(np.hstack(list(kwargs_.values())),return_index=True,axis=0)
|
_,idx = np.unique(np.hstack(list(kwargs.values())),return_index=True,axis=0)
|
||||||
idx = np.sort(idx)
|
idx = np.sort(idx)
|
||||||
kwargs_ = {k:np.atleast_1d(v[idx].squeeze()) for k,v in kwargs_.items()}
|
kwargs = {k:np.atleast_1d(v[idx].squeeze()) for k,v in kwargs.items()}
|
||||||
for what in ['phase','homogenization']:
|
|
||||||
if what not in kwargs_: kwargs_[what] = what+'_label'
|
|
||||||
|
|
||||||
return ConfigMaterial().material_add(**kwargs_)
|
return ConfigMaterial().material_add(**kwargs)
|
||||||
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
@ -361,7 +395,7 @@ class ConfigMaterial(Config):
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
mapping: dictionary
|
mapping: dict
|
||||||
Mapping from old name to new name
|
Mapping from old name to new name
|
||||||
ID: list of ints, optional
|
ID: list of ints, optional
|
||||||
Limit renaming to selected material IDs.
|
Limit renaming to selected material IDs.
|
||||||
|
@ -394,7 +428,7 @@ class ConfigMaterial(Config):
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
mapping: dictionary
|
mapping: dict
|
||||||
Mapping from old name to new name
|
Mapping from old name to new name
|
||||||
ID: list of ints, optional
|
ID: list of ints, optional
|
||||||
Limit renaming to selected homogenization IDs.
|
Limit renaming to selected homogenization IDs.
|
||||||
|
@ -416,11 +450,11 @@ class ConfigMaterial(Config):
|
||||||
|
|
||||||
|
|
||||||
def material_add(self,*,
|
def material_add(self,*,
|
||||||
homogenization: Any = None,
|
homogenization: Optional[Union[str,StrSequence]] = None,
|
||||||
phase: Any = None,
|
phase: Optional[Union[str,StrSequence]] = None,
|
||||||
v: Any = None,
|
v: Optional[Union[float,FloatSequence]] = None,
|
||||||
O: Any = None,
|
O: Optional[Union[float,FloatSequence]] = None,
|
||||||
V_e: Any = None) -> 'ConfigMaterial':
|
V_e: Optional[Union[float,FloatSequence]] = None) -> 'ConfigMaterial':
|
||||||
"""
|
"""
|
||||||
Add material entries.
|
Add material entries.
|
||||||
|
|
||||||
|
@ -432,6 +466,7 @@ class ConfigMaterial(Config):
|
||||||
Phase label (per constituent).
|
Phase label (per constituent).
|
||||||
v: (array-like) of float, optional
|
v: (array-like) of float, optional
|
||||||
Constituent volume fraction (per constituent).
|
Constituent volume fraction (per constituent).
|
||||||
|
Defaults to 1/N_constituent.
|
||||||
O: (array-like) of damask.Rotation or np.array/list of shape(4), optional
|
O: (array-like) of damask.Rotation or np.array/list of shape(4), optional
|
||||||
Orientation as unit quaternion (per constituent).
|
Orientation as unit quaternion (per constituent).
|
||||||
V_e: (array-like) of np.array/list of shape(3,3), optional
|
V_e: (array-like) of np.array/list of shape(3,3), optional
|
||||||
|
@ -444,9 +479,8 @@ class ConfigMaterial(Config):
|
||||||
|
|
||||||
Notes
|
Notes
|
||||||
-----
|
-----
|
||||||
First index of array-like values that are defined per
|
First index of array-like values that are defined per constituent
|
||||||
consituent runs over materials, whereas second index runs
|
runs over materials, whereas second index runs over constituents.
|
||||||
over constituents.
|
|
||||||
|
|
||||||
Examples
|
Examples
|
||||||
--------
|
--------
|
||||||
|
@ -525,49 +559,48 @@ class ConfigMaterial(Config):
|
||||||
phase: {Austenite: null, Ferrite: null}
|
phase: {Austenite: null, Ferrite: null}
|
||||||
|
|
||||||
"""
|
"""
|
||||||
kwargs = {}
|
dim = {'O':(4,),'V_e':(3,3,)}
|
||||||
for keyword,value in zip(['homogenization','phase','v','O','V_e'],[homogenization,phase,v,O,V_e]):
|
ex = dict((keyword, -len(val)) for keyword,val in dim.items())
|
||||||
if value is not None: kwargs[keyword] = value
|
|
||||||
|
|
||||||
_constituent_properties = ['phase','O','v','V_e']
|
N_materials,N_constituents = 1,1
|
||||||
_dim = {'O':(4,),'V_e':(3,3,)}
|
shape = {}
|
||||||
_ex = dict((k, -len(v)) for k, v in _dim.items())
|
for arg,val in zip(['homogenization','phase','v','O','V_e'],[homogenization,phase,v,O,V_e]):
|
||||||
|
if val is None: continue
|
||||||
|
shape[arg] = np.array(val)
|
||||||
|
s = shape[arg].shape[:ex.get(arg,None)] # type: ignore
|
||||||
|
N_materials = max(N_materials,s[0]) if len(s)>0 else N_materials
|
||||||
|
N_constituents = max(N_constituents,s[1]) if len(s)>1 else N_constituents
|
||||||
|
|
||||||
N,n = 1,1
|
shape['v'] = np.array(shape.get('v',1./N_constituents),float)
|
||||||
shaped : Dict[str, Union[None,np.ndarray]] = \
|
|
||||||
{'v': None,
|
|
||||||
'phase': None,
|
|
||||||
'homogenization': None,
|
|
||||||
}
|
|
||||||
|
|
||||||
for k,v in kwargs.items():
|
mat: Sequence[dict] = [{'constituents':[{} for _ in range(N_constituents)]} for _ in range(N_materials)]
|
||||||
shaped[k] = np.array(v)
|
|
||||||
s = shaped[k].shape[:_ex.get(k,None)] # type: ignore
|
|
||||||
N = max(N,s[0]) if len(s)>0 else N
|
|
||||||
n = max(n,s[1]) if len(s)>1 else n
|
|
||||||
|
|
||||||
shaped['v'] = np.array(1./n) if shaped['v'] is None else shaped['v']
|
for k,v in shape.items():
|
||||||
|
target = (N_materials,N_constituents) + dim.get(k,())
|
||||||
mat: Sequence[dict] = [{'constituents':[{} for _ in range(n)]} for _ in range(N)]
|
broadcasted = np.broadcast_to(np.array(v).reshape(util.shapeshifter(np.array(v).shape,target,'right')),target)
|
||||||
|
if k == 'v':
|
||||||
for k,v in shaped.items():
|
if np.min(broadcasted) < 0 or np.max(broadcasted) > 1:
|
||||||
target = (N,n) + _dim.get(k,())
|
raise ValueError('volume fraction "v" out of range')
|
||||||
obj = np.broadcast_to(np.array(v).reshape(util.shapeshifter(() if v is None else v.shape,
|
if len(np.atleast_1d(broadcasted)) > 1:
|
||||||
target,
|
total = np.sum(broadcasted,axis=-1)
|
||||||
mode = 'right')),
|
if np.min(total) < 0 or np.max(total) > 1:
|
||||||
target)
|
raise ValueError('volume fraction "v" out of range')
|
||||||
for i in range(N):
|
if k == 'O' and not np.allclose(1.0,np.linalg.norm(broadcasted,axis=-1)):
|
||||||
if k in _constituent_properties:
|
raise ValueError('orientation "O" is not a unit quaterion')
|
||||||
for j in range(n):
|
elif k == 'V_e' and not np.allclose(broadcasted,tensor.symmetric(broadcasted)):
|
||||||
mat[i]['constituents'][j][k] = obj[i,j].item() if isinstance(obj[i,j],np.generic) else obj[i,j]
|
raise ValueError('elastic stretch "V_e" is not symmetric')
|
||||||
|
for i in range(N_materials):
|
||||||
|
if k == 'homogenization':
|
||||||
|
mat[i][k] = broadcasted[i,0]
|
||||||
else:
|
else:
|
||||||
mat[i][k] = obj[i,0].item() if isinstance(obj[i,0],np.generic) else obj[i,0]
|
for j in range(N_constituents):
|
||||||
|
mat[i]['constituents'][j][k] = broadcasted[i,j]
|
||||||
|
|
||||||
dup = self.copy()
|
dup = self.copy()
|
||||||
dup['material'] = dup['material'] + mat if 'material' in dup else mat
|
dup['material'] = dup['material'] + mat if 'material' in dup else mat
|
||||||
|
|
||||||
for what in [item for item in ['phase','homogenization'] if shaped[item] is not None]:
|
for what in [item for item in ['phase','homogenization'] if item in shape]:
|
||||||
for k in np.unique(shaped[what]): # type: ignore
|
for k in np.unique(shape[what]): # type: ignore
|
||||||
if k not in dup[what]: dup[what][str(k)] = None
|
if k not in dup[what]: dup[what][str(k)] = None
|
||||||
|
|
||||||
return dup
|
return dup
|
||||||
|
|
|
@ -307,15 +307,13 @@ class Crystal():
|
||||||
Cubic crystal family:
|
Cubic crystal family:
|
||||||
|
|
||||||
>>> import damask
|
>>> import damask
|
||||||
>>> cubic = damask.Crystal(family='cubic')
|
>>> (cubic := damask.Crystal(family='cubic'))
|
||||||
>>> cubic
|
|
||||||
Crystal family: cubic
|
Crystal family: cubic
|
||||||
|
|
||||||
Body-centered cubic Bravais lattice with parameters of iron:
|
Body-centered cubic Bravais lattice with parameters of iron:
|
||||||
|
|
||||||
>>> import damask
|
>>> import damask
|
||||||
>>> Fe = damask.Crystal(lattice='cI', a=287e-12)
|
>>> (Fe := damask.Crystal(lattice='cI', a=287e-12))
|
||||||
>>> Fe
|
|
||||||
Crystal family: cubic
|
Crystal family: cubic
|
||||||
Bravais lattice: cI
|
Bravais lattice: cI
|
||||||
a=2.87e-10 m, b=2.87e-10 m, c=2.87e-10 m
|
a=2.87e-10 m, b=2.87e-10 m, c=2.87e-10 m
|
||||||
|
@ -406,7 +404,7 @@ class Crystal():
|
||||||
"""
|
"""
|
||||||
Return repr(self).
|
Return repr(self).
|
||||||
|
|
||||||
Give short human-readable summary.
|
Give short, human-readable summary.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
family = f'Crystal family: {self.family}'
|
family = f'Crystal family: {self.family}'
|
||||||
|
|
|
@ -32,10 +32,10 @@ class Grid:
|
||||||
"""
|
"""
|
||||||
Geometry definition for grid solvers.
|
Geometry definition for grid solvers.
|
||||||
|
|
||||||
Create and manipulate geometry definitions for storage as VTK
|
Create and manipulate geometry definitions for storage as VTK ImageData
|
||||||
image data files ('.vti' extension). A grid contains the
|
files ('.vti' extension). A grid has a physical size, a coordinate origin,
|
||||||
material ID (referring to the entry in 'material.yaml') and
|
and contains the material ID (indexing an entry in 'material.yaml')
|
||||||
the physical size.
|
as well as initial condition fields.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
|
@ -57,7 +57,7 @@ class Grid:
|
||||||
origin : sequence of float, len (3), optional
|
origin : sequence of float, len (3), optional
|
||||||
Coordinates of grid origin in meter. Defaults to [0.0,0.0,0.0].
|
Coordinates of grid origin in meter. Defaults to [0.0,0.0,0.0].
|
||||||
initial_conditions : dictionary, optional
|
initial_conditions : dictionary, optional
|
||||||
Labels and values of the inital conditions at each material point.
|
Initial condition label and field values at each grid point.
|
||||||
comments : (sequence of) str, optional
|
comments : (sequence of) str, optional
|
||||||
Additional, human-readable information, e.g. history of operations.
|
Additional, human-readable information, e.g. history of operations.
|
||||||
|
|
||||||
|
@ -74,7 +74,7 @@ class Grid:
|
||||||
"""
|
"""
|
||||||
Return repr(self).
|
Return repr(self).
|
||||||
|
|
||||||
Give short human-readable summary.
|
Give short, human-readable summary.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
mat_min = np.nanmin(self.material)
|
mat_min = np.nanmin(self.material)
|
||||||
|
@ -144,7 +144,7 @@ class Grid:
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def size(self) -> np.ndarray:
|
def size(self) -> np.ndarray:
|
||||||
"""Physical size of grid in meter."""
|
"""Edge lengths of grid in meter."""
|
||||||
return self._size
|
return self._size
|
||||||
|
|
||||||
@size.setter
|
@size.setter
|
||||||
|
@ -157,7 +157,7 @@ class Grid:
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def origin(self) -> np.ndarray:
|
def origin(self) -> np.ndarray:
|
||||||
"""Coordinates of grid origin in meter."""
|
"""Vector to grid origin in meter."""
|
||||||
return self._origin
|
return self._origin
|
||||||
|
|
||||||
@origin.setter
|
@origin.setter
|
||||||
|
@ -186,7 +186,7 @@ class Grid:
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def cells(self) -> np.ndarray:
|
def cells(self) -> np.ndarray:
|
||||||
"""Number of cells in x,y,z direction."""
|
"""Cell counts along x,y,z direction."""
|
||||||
return np.asarray(self.material.shape)
|
return np.asarray(self.material.shape)
|
||||||
|
|
||||||
|
|
||||||
|
@ -199,7 +199,7 @@ class Grid:
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def load(fname: Union[str, Path]) -> 'Grid':
|
def load(fname: Union[str, Path]) -> 'Grid':
|
||||||
"""
|
"""
|
||||||
Load from VTK image data file.
|
Load from VTK ImageData file.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
|
@ -317,6 +317,11 @@ class Grid:
|
||||||
loaded : damask.Grid
|
loaded : damask.Grid
|
||||||
Grid-based geometry from file.
|
Grid-based geometry from file.
|
||||||
|
|
||||||
|
Notes
|
||||||
|
-----
|
||||||
|
Material indices in Neper usually start at 1 unless
|
||||||
|
a buffer material with index 0 is added.
|
||||||
|
|
||||||
Examples
|
Examples
|
||||||
--------
|
--------
|
||||||
Read a periodic polycrystal generated with Neper.
|
Read a periodic polycrystal generated with Neper.
|
||||||
|
@ -325,7 +330,7 @@ class Grid:
|
||||||
>>> N_grains = 20
|
>>> N_grains = 20
|
||||||
>>> cells = (32,32,32)
|
>>> 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.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')
|
>>> damask.Grid.load_Neper(f'n{N_grains}-id1.vtk').renumber()
|
||||||
cells: 32 × 32 × 32
|
cells: 32 × 32 × 32
|
||||||
size: 1.0 × 1.0 × 1.0 m³
|
size: 1.0 × 1.0 × 1.0 m³
|
||||||
origin: 0.0 0.0 0.0 m
|
origin: 0.0 0.0 0.0 m
|
||||||
|
@ -336,7 +341,7 @@ class Grid:
|
||||||
cells = np.array(v.vtk_data.GetDimensions())-1
|
cells = np.array(v.vtk_data.GetDimensions())-1
|
||||||
bbox = np.array(v.vtk_data.GetBounds()).reshape(3,2).T
|
bbox = np.array(v.vtk_data.GetBounds()).reshape(3,2).T
|
||||||
|
|
||||||
return Grid(material = v.get('MaterialId').reshape(cells,order='F').astype('int32',casting='unsafe') - 1,
|
return Grid(material = v.get('MaterialId').reshape(cells,order='F').astype('int32',casting='unsafe'),
|
||||||
size = bbox[1] - bbox[0],
|
size = bbox[1] - bbox[0],
|
||||||
origin = bbox[0],
|
origin = bbox[0],
|
||||||
comments = util.execution_stamp('Grid','load_Neper'),
|
comments = util.execution_stamp('Grid','load_Neper'),
|
||||||
|
@ -470,9 +475,9 @@ class Grid:
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
cells : sequence of int, len (3)
|
cells : sequence of int, len (3)
|
||||||
Number of cells in x,y,z direction.
|
Cell counts along x,y,z direction.
|
||||||
size : sequence of float, len (3)
|
size : sequence of float, len (3)
|
||||||
Physical size of the grid in meter.
|
Edge lengths of the grid in meter.
|
||||||
seeds : numpy.ndarray of float, shape (:,3)
|
seeds : numpy.ndarray of float, shape (:,3)
|
||||||
Position of the seed points in meter. All points need to lay within the box.
|
Position of the seed points in meter. All points need to lay within the box.
|
||||||
weights : sequence of float, len (seeds.shape[0])
|
weights : sequence of float, len (seeds.shape[0])
|
||||||
|
@ -527,9 +532,9 @@ class Grid:
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
cells : sequence of int, len (3)
|
cells : sequence of int, len (3)
|
||||||
Number of cells in x,y,z direction.
|
Cell counts along x,y,z direction.
|
||||||
size : sequence of float, len (3)
|
size : sequence of float, len (3)
|
||||||
Physical size of the grid in meter.
|
Edge lengths of the grid in meter.
|
||||||
seeds : numpy.ndarray of float, shape (:,3)
|
seeds : numpy.ndarray of float, shape (:,3)
|
||||||
Position of the seed points in meter. All points need to lay within the box.
|
Position of the seed points in meter. All points need to lay within the box.
|
||||||
material : sequence of int, len (seeds.shape[0]), optional
|
material : sequence of int, len (seeds.shape[0]), optional
|
||||||
|
@ -608,14 +613,14 @@ class Grid:
|
||||||
periods: int = 1,
|
periods: int = 1,
|
||||||
materials: IntSequence = (0,1)) -> 'Grid':
|
materials: IntSequence = (0,1)) -> 'Grid':
|
||||||
"""
|
"""
|
||||||
Create grid from definition of triply periodic minimal surface.
|
Create grid from definition of triply-periodic minimal surface.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
cells : sequence of int, len (3)
|
cells : sequence of int, len (3)
|
||||||
Number of cells in x,y,z direction.
|
Cell counts along x,y,z direction.
|
||||||
size : sequence of float, len (3)
|
size : sequence of float, len (3)
|
||||||
Physical size of the grid in meter.
|
Edge lengths of the grid in meter.
|
||||||
surface : str
|
surface : str
|
||||||
Type of the minimal surface. See notes for details.
|
Type of the minimal surface. See notes for details.
|
||||||
threshold : float, optional.
|
threshold : float, optional.
|
||||||
|
@ -664,19 +669,19 @@ class Grid:
|
||||||
>>> import numpy as np
|
>>> import numpy as np
|
||||||
>>> import damask
|
>>> import damask
|
||||||
>>> damask.Grid.from_minimal_surface([64]*3,np.ones(3)*1.e-4,'Gyroid')
|
>>> damask.Grid.from_minimal_surface([64]*3,np.ones(3)*1.e-4,'Gyroid')
|
||||||
cells : 64 x 64 x 64
|
cells : 64 × 64 × 64
|
||||||
size : 0.0001 x 0.0001 x 0.0001 m³
|
size : 0.0001 × 0.0001 × 0.0001 m³
|
||||||
origin: 0.0 0.0 0.0 m
|
origin: 0.0 0.0 0.0 m
|
||||||
# materials: 2
|
# materials: 2
|
||||||
|
|
||||||
Minimal surface of 'Neovius' type with non-default material IDs.
|
Minimal surface of 'Neovius' type with specific material IDs.
|
||||||
|
|
||||||
>>> import numpy as np
|
>>> import numpy as np
|
||||||
>>> import damask
|
>>> import damask
|
||||||
>>> damask.Grid.from_minimal_surface([80]*3,np.ones(3)*5.e-4,
|
>>> damask.Grid.from_minimal_surface([80]*3,np.ones(3)*5.e-4,
|
||||||
... 'Neovius',materials=(1,5))
|
... 'Neovius',materials=(1,5))
|
||||||
cells : 80 x 80 x 80
|
cells : 80 × 80 × 80
|
||||||
size : 0.0005 x 0.0005 x 0.0005 m³
|
size : 0.0005 × 0.0005 × 0.0005 m³
|
||||||
origin: 0.0 0.0 0.0 m
|
origin: 0.0 0.0 0.0 m
|
||||||
# materials: 2 (min: 1, max: 5)
|
# materials: 2 (min: 1, max: 5)
|
||||||
|
|
||||||
|
@ -695,12 +700,13 @@ class Grid:
|
||||||
fname: Union[str, Path],
|
fname: Union[str, Path],
|
||||||
compress: bool = True):
|
compress: bool = True):
|
||||||
"""
|
"""
|
||||||
Save as VTK image data file.
|
Save as VTK ImageData file.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
fname : str or pathlib.Path
|
fname : str or pathlib.Path
|
||||||
Filename to write. Valid extension is .vti, it will be appended if not given.
|
Filename to write.
|
||||||
|
Valid extension is .vti, which will be appended if not given.
|
||||||
compress : bool, optional
|
compress : bool, optional
|
||||||
Compress with zlib algorithm. Defaults to True.
|
Compress with zlib algorithm. Defaults to True.
|
||||||
|
|
||||||
|
@ -727,7 +733,7 @@ class Grid:
|
||||||
fname : str or file handle
|
fname : str or file handle
|
||||||
Geometry file to write with extension '.geom'.
|
Geometry file to write with extension '.geom'.
|
||||||
compress : bool, optional
|
compress : bool, optional
|
||||||
Compress geometry with 'x of y' and 'a to b'.
|
Compress geometry using 'x of y' and 'a to b'.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
warnings.warn('Support for ASCII-based geom format will be removed in DAMASK 3.0.0', DeprecationWarning,2)
|
warnings.warn('Support for ASCII-based geom format will be removed in DAMASK 3.0.0', DeprecationWarning,2)
|
||||||
|
@ -771,13 +777,13 @@ class Grid:
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
cells : sequence of int, len (3), optional
|
cells : sequence of int, len (3), optional
|
||||||
Number of cells x,y,z direction.
|
Cell counts along x,y,z direction.
|
||||||
offset : sequence of int, len (3), optional
|
offset : sequence of int, len (3), optional
|
||||||
Offset (measured in cells) from old to new grid.
|
Offset (measured in cells) from old to new grid.
|
||||||
Defaults to [0,0,0].
|
Defaults to [0,0,0].
|
||||||
fill : int, optional
|
fill : int, optional
|
||||||
Material ID to fill the background.
|
Material ID to fill the background.
|
||||||
Defaults to material.max() + 1.
|
Defaults to material.max()+1.
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
-------
|
-------
|
||||||
|
@ -790,11 +796,11 @@ class Grid:
|
||||||
|
|
||||||
>>> import numpy as np
|
>>> import numpy as np
|
||||||
>>> import damask
|
>>> import damask
|
||||||
>>> g = damask.Grid(np.zeros([32]*3,int),np.ones(3)*1e-4)
|
>>> g = damask.Grid(np.zeros([32]*3,int),np.ones(3)*1e-3)
|
||||||
>>> g.canvas([32,32,16],[0,0,16])
|
>>> g.canvas([32,32,16],[0,0,16])
|
||||||
cells : 33 x 32 x 16
|
cells: 32 × 32 × 16
|
||||||
size : 0.0001 x 0.0001 x 5e-05 m³
|
size: 0.001 × 0.001 × 0.0005 m³
|
||||||
origin: 0.0 0.0 5e-05 m
|
origin: 0.0 0.0 0.0005 m
|
||||||
# materials: 1
|
# materials: 1
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
@ -837,16 +843,33 @@ class Grid:
|
||||||
|
|
||||||
Examples
|
Examples
|
||||||
--------
|
--------
|
||||||
Mirror along x- and y-direction.
|
Mirror along y-direction.
|
||||||
|
|
||||||
>>> import numpy as np
|
>>> import numpy as np
|
||||||
>>> import damask
|
>>> import damask
|
||||||
>>> g = damask.Grid(np.zeros([32]*3,int),np.ones(3)*1e-4)
|
>>> (g := damask.Grid(np.arange(4*5*6).reshape([4,5,6]),np.ones(3)))
|
||||||
>>> g.mirror('xy',True)
|
cells: 4 × 5 × 6
|
||||||
cells : 64 x 64 x 32
|
size: 1.0 × 1.0 × 1.0 m³
|
||||||
size : 0.0002 x 0.0002 x 0.0001 m³
|
|
||||||
origin: 0.0 0.0 0.0 m
|
origin: 0.0 0.0 0.0 m
|
||||||
# materials: 1
|
# materials: 120
|
||||||
|
>>> g.mirror('y')
|
||||||
|
cells: 4 × 8 × 6
|
||||||
|
size: 1.0 × 1.6 × 1.0 m³
|
||||||
|
origin: 0.0 0.0 0.0 m
|
||||||
|
# materials: 120
|
||||||
|
|
||||||
|
Reflect along x- and y-direction.
|
||||||
|
|
||||||
|
>>> g.mirror('xy',reflect=True)
|
||||||
|
cells: 8 × 10 × 6
|
||||||
|
size: 2.0 × 2.0 × 1.0 m³
|
||||||
|
origin: 0.0 0.0 0.0 m
|
||||||
|
# materials: 120
|
||||||
|
|
||||||
|
Independence of mirroring order.
|
||||||
|
|
||||||
|
>>> g.mirror('xy') == g.mirror(['y','x'])
|
||||||
|
True
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if not set(directions).issubset(valid := ['x', 'y', 'z']):
|
if not set(directions).issubset(valid := ['x', 'y', 'z']):
|
||||||
|
@ -884,11 +907,29 @@ class Grid:
|
||||||
updated : damask.Grid
|
updated : damask.Grid
|
||||||
Updated grid-based geometry.
|
Updated grid-based geometry.
|
||||||
|
|
||||||
|
Examples
|
||||||
|
--------
|
||||||
|
Invariance of flipping order.
|
||||||
|
|
||||||
|
>>> import numpy as np
|
||||||
|
>>> import damask
|
||||||
|
>>> (g := damask.Grid(np.arange(4*5*6).reshape([4,5,6]),np.ones(3)))
|
||||||
|
cells: 4 × 5 × 6
|
||||||
|
size: 1.0 × 1.0 × 1.0 m³
|
||||||
|
origin: 0.0 0.0 0.0 m
|
||||||
|
# materials: 120
|
||||||
|
>>> g.flip('xyz') == g.flip(['x','z','y'])
|
||||||
|
True
|
||||||
|
|
||||||
|
Invariance of flipping a (fully) mirrored grid.
|
||||||
|
|
||||||
|
>>> g.mirror('x',True) == g.mirror('x',True).flip('x')
|
||||||
|
True
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if not set(directions).issubset(valid := ['x', 'y', 'z']):
|
if not set(directions).issubset(valid := ['x', 'y', 'z']):
|
||||||
raise ValueError(f'invalid direction "{set(directions).difference(valid)}" specified')
|
raise ValueError(f'invalid direction "{set(directions).difference(valid)}" specified')
|
||||||
|
|
||||||
|
|
||||||
mat = np.flip(self.material, [valid.index(d) for d in directions if d in valid])
|
mat = np.flip(self.material, [valid.index(d) for d in directions if d in valid])
|
||||||
|
|
||||||
return Grid(material = mat,
|
return Grid(material = mat,
|
||||||
|
@ -902,7 +943,7 @@ class Grid:
|
||||||
R: Rotation,
|
R: Rotation,
|
||||||
fill: Optional[int] = None) -> 'Grid':
|
fill: Optional[int] = None) -> 'Grid':
|
||||||
"""
|
"""
|
||||||
Rotate grid (and pad if required).
|
Rotate grid (possibly extending its bounding box).
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
|
@ -910,13 +951,27 @@ class Grid:
|
||||||
Rotation to apply to the grid.
|
Rotation to apply to the grid.
|
||||||
fill : int, optional
|
fill : int, optional
|
||||||
Material ID to fill enlarged bounding box.
|
Material ID to fill enlarged bounding box.
|
||||||
Defaults to material.max() + 1.
|
Defaults to material.max()+1.
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
-------
|
-------
|
||||||
updated : damask.Grid
|
updated : damask.Grid
|
||||||
Updated grid-based geometry.
|
Updated grid-based geometry.
|
||||||
|
|
||||||
|
Examples
|
||||||
|
--------
|
||||||
|
Rotation by 180° (π) is equivalent to twice flipping.
|
||||||
|
|
||||||
|
>>> import numpy as np
|
||||||
|
>>> import damask
|
||||||
|
>>> (g := damask.Grid(np.arange(4*5*6).reshape([4,5,6]),np.ones(3)))
|
||||||
|
cells: 4 × 5 × 6
|
||||||
|
size: 1.0 × 1.0 × 1.0 m³
|
||||||
|
origin: 0.0 0.0 0.0 m
|
||||||
|
# materials: 120
|
||||||
|
>>> g.rotate(damask.Rotation.from_axis_angle([0,0,1,180],degrees=True)) == g.flip('xy')
|
||||||
|
True
|
||||||
|
|
||||||
"""
|
"""
|
||||||
material = self.material
|
material = self.material
|
||||||
# These rotations are always applied in the reference coordinate system, i.e. (z,x,z) not (z,x',z'')
|
# These rotations are always applied in the reference coordinate system, i.e. (z,x,z) not (z,x',z'')
|
||||||
|
@ -941,12 +996,12 @@ class Grid:
|
||||||
def scale(self,
|
def scale(self,
|
||||||
cells: IntSequence) -> 'Grid':
|
cells: IntSequence) -> 'Grid':
|
||||||
"""
|
"""
|
||||||
Scale grid to new cell count.
|
Scale grid to new cell counts.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
cells : sequence of int, len (3)
|
cells : sequence of int, len (3)
|
||||||
Number of cells in x,y,z direction.
|
Cell counts along x,y,z direction.
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
-------
|
-------
|
||||||
|
@ -955,7 +1010,7 @@ class Grid:
|
||||||
|
|
||||||
Examples
|
Examples
|
||||||
--------
|
--------
|
||||||
Double resolution.
|
Double grid resolution.
|
||||||
|
|
||||||
>>> import numpy as np
|
>>> import numpy as np
|
||||||
>>> import damask
|
>>> import damask
|
||||||
|
@ -965,8 +1020,8 @@ class Grid:
|
||||||
origin: 0.0 0.0 0.0 m
|
origin: 0.0 0.0 0.0 m
|
||||||
# materials: 1
|
# materials: 1
|
||||||
>>> g.scale(g.cells*2)
|
>>> g.scale(g.cells*2)
|
||||||
cells : 64 x 64 x 64
|
cells : 64 × 64 × 64
|
||||||
size : 0.0001 x 0.0001 x 0.0001 m³
|
size : 0.0001 × 0.0001 × 0.0001 m³
|
||||||
origin: 0.0 0.0 0.0 m
|
origin: 0.0 0.0 0.0 m
|
||||||
# materials: 1
|
# materials: 1
|
||||||
|
|
||||||
|
@ -994,7 +1049,7 @@ class Grid:
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
idx : numpy.ndarray of int, shape (:,:,:) or (:,:,:,3)
|
idx : numpy.ndarray of int, shape (:,:,:) or (:,:,:,3)
|
||||||
Grid of flat indices or coordinate indices.
|
Grid of flat indices or coordinate indices.
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
-------
|
-------
|
||||||
|
@ -1069,7 +1124,7 @@ class Grid:
|
||||||
|
|
||||||
def sort(self) -> 'Grid':
|
def sort(self) -> 'Grid':
|
||||||
"""
|
"""
|
||||||
Sort material indices such that min(material) is located at (0,0,0).
|
Sort material indices such that min(material ID) is located at (0,0,0).
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
-------
|
-------
|
||||||
|
@ -1186,7 +1241,7 @@ class Grid:
|
||||||
fill : int, optional
|
fill : int, optional
|
||||||
Fill value for primitive. Defaults to material.max()+1.
|
Fill value for primitive. Defaults to material.max()+1.
|
||||||
R : damask.Rotation, optional
|
R : damask.Rotation, optional
|
||||||
Rotation of primitive. Defaults to no rotation.
|
Rotation of the primitive. Defaults to no rotation.
|
||||||
inverse : bool, optional
|
inverse : bool, optional
|
||||||
Retain original materials within primitive and fill outside.
|
Retain original materials within primitive and fill outside.
|
||||||
Defaults to False.
|
Defaults to False.
|
||||||
|
@ -1206,8 +1261,8 @@ class Grid:
|
||||||
>>> import damask
|
>>> import damask
|
||||||
>>> g = damask.Grid(np.zeros([64]*3,int), np.ones(3)*1e-4)
|
>>> g = damask.Grid(np.zeros([64]*3,int), np.ones(3)*1e-4)
|
||||||
>>> g.add_primitive(np.ones(3)*5e-5,np.ones(3)*5e-5,1)
|
>>> g.add_primitive(np.ones(3)*5e-5,np.ones(3)*5e-5,1)
|
||||||
cells : 64 x 64 x 64
|
cells : 64 × 64 × 64
|
||||||
size : 0.0001 x 0.0001 x 0.0001 m³
|
size : 0.0001 × 0.0001 × 0.0001 m³
|
||||||
origin: 0.0 0.0 0.0 m
|
origin: 0.0 0.0 0.0 m
|
||||||
# materials: 2
|
# materials: 2
|
||||||
|
|
||||||
|
@ -1217,8 +1272,8 @@ class Grid:
|
||||||
>>> import damask
|
>>> import damask
|
||||||
>>> g = damask.Grid(np.zeros([64]*3,int), np.ones(3)*1e-4)
|
>>> g = damask.Grid(np.zeros([64]*3,int), np.ones(3)*1e-4)
|
||||||
>>> g.add_primitive(np.ones(3,int)*32,np.zeros(3),np.inf)
|
>>> g.add_primitive(np.ones(3,int)*32,np.zeros(3),np.inf)
|
||||||
cells : 64 x 64 x 64
|
cells : 64 × 64 × 64
|
||||||
size : 0.0001 x 0.0001 x 0.0001 m³
|
size : 0.0001 × 0.0001 × 0.0001 m³
|
||||||
origin: 0.0 0.0 0.0 m
|
origin: 0.0 0.0 0.0 m
|
||||||
# materials: 2
|
# materials: 2
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,78 @@
|
||||||
|
from typing import Optional, Union, Dict, Any, List
|
||||||
|
|
||||||
|
from numpy import ma
|
||||||
|
import yaml
|
||||||
|
|
||||||
|
from ._typehints import FileHandle
|
||||||
|
from ._config import NiceDumper
|
||||||
|
from . import util
|
||||||
|
from . import Config
|
||||||
|
|
||||||
|
|
||||||
|
class MaskedMatrixDumper(NiceDumper):
|
||||||
|
"""Format masked matrices."""
|
||||||
|
|
||||||
|
def represent_data(self, data: Any):
|
||||||
|
return super().represent_data(data.astype(object).filled('x') if isinstance(data, ma.core.MaskedArray) else data) # type: ignore[attr-defined]
|
||||||
|
|
||||||
|
|
||||||
|
class LoadcaseGrid(Config):
|
||||||
|
"""Load case for grid solver."""
|
||||||
|
|
||||||
|
def __init__(self,
|
||||||
|
config: Optional[Union[str,Dict[str,Any]]] = None,
|
||||||
|
*,
|
||||||
|
solver: Optional[Dict[str,str]] = None,
|
||||||
|
loadstep: Optional[List[Dict[str,Any]]] = None):
|
||||||
|
"""
|
||||||
|
New grid solver load case.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
config : dict or str, optional
|
||||||
|
Grid solver load case. String needs to be valid YAML.
|
||||||
|
solver : dict, optional
|
||||||
|
Solver configuration.
|
||||||
|
Defaults to an empty dict if 'config' is not given.
|
||||||
|
loadstep : list of dict, optional
|
||||||
|
Load step configuration.
|
||||||
|
Defaults to an empty list if 'config' is not given.
|
||||||
|
|
||||||
|
"""
|
||||||
|
kwargs: Dict[str,Union[Dict[str,str],List[Dict[str,Any]]]] = {}
|
||||||
|
default: Union[List,Dict]
|
||||||
|
for arg,value,default in [('solver',solver,{}),('loadstep',loadstep,[])]: # type: ignore[assignment]
|
||||||
|
if value is not None:
|
||||||
|
kwargs[arg] = value
|
||||||
|
elif config is None:
|
||||||
|
kwargs[arg] = default
|
||||||
|
|
||||||
|
super().__init__(config,**kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
def save(self,
|
||||||
|
fname: FileHandle,
|
||||||
|
**kwargs):
|
||||||
|
"""
|
||||||
|
Save to YAML file.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
fname : file, str, or pathlib.Path
|
||||||
|
Filename or file to write.
|
||||||
|
**kwargs : dict
|
||||||
|
Keyword arguments parsed to yaml.dump.
|
||||||
|
|
||||||
|
"""
|
||||||
|
for key,default in dict(width=256,
|
||||||
|
default_flow_style=None,
|
||||||
|
sort_keys=False).items():
|
||||||
|
if key not in kwargs:
|
||||||
|
kwargs[key] = default
|
||||||
|
|
||||||
|
fhandle = util.open_text(fname,'w')
|
||||||
|
try:
|
||||||
|
fhandle.write(yaml.dump(self,Dumper=MaskedMatrixDumper,**kwargs))
|
||||||
|
except TypeError: # compatibility with old pyyaml
|
||||||
|
del kwargs['sort_keys']
|
||||||
|
fhandle.write(yaml.dump(self,Dumper=MaskedMatrixDumper,**kwargs))
|
|
@ -1,6 +1,5 @@
|
||||||
import inspect
|
|
||||||
import copy
|
import copy
|
||||||
from typing import Optional, Union, Callable, Dict, Any, Tuple, TypeVar
|
from typing import Optional, Union, TypeVar
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
|
@ -10,31 +9,6 @@ from . import Crystal
|
||||||
from . import util
|
from . import util
|
||||||
from . import tensor
|
from . import tensor
|
||||||
|
|
||||||
|
|
||||||
_parameter_doc = \
|
|
||||||
"""
|
|
||||||
family : {'triclinic', 'monoclinic', 'orthorhombic', 'tetragonal', 'hexagonal', 'cubic'}, optional.
|
|
||||||
Name of the crystal family.
|
|
||||||
Family will be inferred if 'lattice' is given.
|
|
||||||
lattice : {'aP', 'mP', 'mS', 'oP', 'oS', 'oI', 'oF', 'tP', 'tI', 'hP', 'cP', 'cI', 'cF'}, optional.
|
|
||||||
Name of the Bravais lattice in Pearson notation.
|
|
||||||
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.
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
MyType = TypeVar('MyType', bound='Orientation')
|
MyType = TypeVar('MyType', bound='Orientation')
|
||||||
|
|
||||||
class Orientation(Rotation,Crystal):
|
class Orientation(Rotation,Crystal):
|
||||||
|
@ -94,7 +68,7 @@ class Orientation(Rotation,Crystal):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@util.extend_docstring(extra_parameters=_parameter_doc)
|
@util.extend_docstring(adopted_parameters=Crystal.__init__)
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
rotation: Union[FloatSequence, Rotation] = np.array([1.,0.,0.,0.]),
|
rotation: Union[FloatSequence, Rotation] = np.array([1.,0.,0.,0.]),
|
||||||
*,
|
*,
|
||||||
|
@ -108,7 +82,7 @@ class Orientation(Rotation,Crystal):
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
rotation : list, numpy.ndarray, Rotation, optional
|
rotation : list, numpy.ndarray, or Rotation, optional
|
||||||
Unit quaternion in positive real hemisphere.
|
Unit quaternion in positive real hemisphere.
|
||||||
Use .from_quaternion to perform a sanity check.
|
Use .from_quaternion to perform a sanity check.
|
||||||
Defaults to no rotation.
|
Defaults to no rotation.
|
||||||
|
@ -123,7 +97,7 @@ class Orientation(Rotation,Crystal):
|
||||||
"""
|
"""
|
||||||
Return repr(self).
|
Return repr(self).
|
||||||
|
|
||||||
Give short human-readable summary.
|
Give short, human-readable summary.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
return util.srepr([Crystal.__repr__(self),
|
return util.srepr([Crystal.__repr__(self),
|
||||||
|
@ -261,134 +235,91 @@ class Orientation(Rotation,Crystal):
|
||||||
Compound rotation self*other, i.e. first other then self rotation.
|
Compound rotation self*other, i.e. first other then self rotation.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if isinstance(other, (Orientation,Rotation)):
|
if not isinstance(other, (Orientation,Rotation)):
|
||||||
return self.copy(Rotation(self.quaternion)*Rotation(other.quaternion))
|
|
||||||
else:
|
|
||||||
raise TypeError('use "O@b", i.e. matmul, to apply Orientation "O" to object "b"')
|
raise TypeError('use "O@b", i.e. matmul, to apply Orientation "O" to object "b"')
|
||||||
|
return self.copy(Rotation(self.quaternion)*Rotation(other.quaternion))
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _split_kwargs(kwargs: Dict[str, Any],
|
|
||||||
target: Callable) -> Tuple[Dict[str, Any], ...]:
|
|
||||||
"""
|
|
||||||
Separate keyword arguments in 'kwargs' targeted at 'target' from general keyword arguments of Orientation objects.
|
|
||||||
|
|
||||||
Parameters
|
|
||||||
----------
|
|
||||||
kwargs : dictionary
|
|
||||||
Contains all **kwargs.
|
|
||||||
target: method
|
|
||||||
Function to scan for kwarg signature.
|
|
||||||
|
|
||||||
Returns
|
|
||||||
-------
|
|
||||||
rot_kwargs: dictionary
|
|
||||||
Valid keyword arguments of 'target' function of Rotation class.
|
|
||||||
ori_kwargs: dictionary
|
|
||||||
Valid keyword arguments of Orientation object.
|
|
||||||
|
|
||||||
"""
|
|
||||||
kws: Tuple[Dict[str, Any], ...] = ()
|
|
||||||
for t in (target,Orientation.__init__):
|
|
||||||
kws += ({key: kwargs[key] for key in set(inspect.signature(t).parameters) & set(kwargs)},)
|
|
||||||
|
|
||||||
invalid_keys = set(kwargs)-(set(kws[0])|set(kws[1]))
|
|
||||||
if invalid_keys:
|
|
||||||
raise TypeError(f"{inspect.stack()[1][3]}() got an unexpected keyword argument '{invalid_keys.pop()}'")
|
|
||||||
|
|
||||||
return kws
|
|
||||||
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@util.extend_docstring(Rotation.from_random,
|
@util.extend_docstring(Rotation.from_random,
|
||||||
extra_parameters=_parameter_doc)
|
adopted_parameters=Crystal.__init__)
|
||||||
|
@util.pass_on('rotation', Rotation.from_random, wrapped=__init__)
|
||||||
def from_random(cls, **kwargs) -> 'Orientation':
|
def from_random(cls, **kwargs) -> 'Orientation':
|
||||||
kwargs_rot,kwargs_ori = Orientation._split_kwargs(kwargs,Rotation.from_random)
|
return cls(**kwargs)
|
||||||
return cls(rotation=Rotation.from_random(**kwargs_rot),**kwargs_ori)
|
|
||||||
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@util.extend_docstring(Rotation.from_quaternion,
|
@util.extend_docstring(Rotation.from_quaternion,
|
||||||
extra_parameters=_parameter_doc)
|
adopted_parameters=Crystal.__init__)
|
||||||
|
@util.pass_on('rotation', Rotation.from_quaternion, wrapped=__init__)
|
||||||
def from_quaternion(cls, **kwargs) -> 'Orientation':
|
def from_quaternion(cls, **kwargs) -> 'Orientation':
|
||||||
kwargs_rot,kwargs_ori = Orientation._split_kwargs(kwargs,Rotation.from_quaternion)
|
return cls(**kwargs)
|
||||||
return cls(rotation=Rotation.from_quaternion(**kwargs_rot),**kwargs_ori)
|
|
||||||
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@util.extend_docstring(Rotation.from_Euler_angles,
|
@util.extend_docstring(Rotation.from_Euler_angles,
|
||||||
extra_parameters=_parameter_doc)
|
adopted_parameters=Crystal.__init__)
|
||||||
|
@util.pass_on('rotation', Rotation.from_Euler_angles, wrapped=__init__)
|
||||||
def from_Euler_angles(cls, **kwargs) -> 'Orientation':
|
def from_Euler_angles(cls, **kwargs) -> 'Orientation':
|
||||||
kwargs_rot,kwargs_ori = Orientation._split_kwargs(kwargs,Rotation.from_Euler_angles)
|
return cls(**kwargs)
|
||||||
return cls(rotation=Rotation.from_Euler_angles(**kwargs_rot),**kwargs_ori)
|
|
||||||
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@util.extend_docstring(Rotation.from_axis_angle,
|
@util.extend_docstring(Rotation.from_axis_angle,
|
||||||
extra_parameters=_parameter_doc)
|
adopted_parameters=Crystal.__init__)
|
||||||
|
@util.pass_on('rotation', Rotation.from_axis_angle, wrapped=__init__)
|
||||||
def from_axis_angle(cls, **kwargs) -> 'Orientation':
|
def from_axis_angle(cls, **kwargs) -> 'Orientation':
|
||||||
kwargs_rot,kwargs_ori = Orientation._split_kwargs(kwargs,Rotation.from_axis_angle)
|
return cls(**kwargs)
|
||||||
return cls(rotation=Rotation.from_axis_angle(**kwargs_rot),**kwargs_ori)
|
|
||||||
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@util.extend_docstring(Rotation.from_basis,
|
@util.extend_docstring(Rotation.from_basis,
|
||||||
extra_parameters=_parameter_doc)
|
adopted_parameters=Crystal.__init__)
|
||||||
|
@util.pass_on('rotation', Rotation.from_basis, wrapped=__init__)
|
||||||
def from_basis(cls, **kwargs) -> 'Orientation':
|
def from_basis(cls, **kwargs) -> 'Orientation':
|
||||||
kwargs_rot,kwargs_ori = Orientation._split_kwargs(kwargs,Rotation.from_basis)
|
return cls(**kwargs)
|
||||||
return cls(rotation=Rotation.from_basis(**kwargs_rot),**kwargs_ori)
|
|
||||||
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@util.extend_docstring(Rotation.from_matrix,
|
@util.extend_docstring(Rotation.from_matrix,
|
||||||
extra_parameters=_parameter_doc)
|
adopted_parameters=Crystal.__init__)
|
||||||
|
@util.pass_on('rotation', Rotation.from_matrix, wrapped=__init__)
|
||||||
def from_matrix(cls, **kwargs) -> 'Orientation':
|
def from_matrix(cls, **kwargs) -> 'Orientation':
|
||||||
kwargs_rot,kwargs_ori = Orientation._split_kwargs(kwargs,Rotation.from_matrix)
|
return cls(**kwargs)
|
||||||
return cls(rotation=Rotation.from_matrix(**kwargs_rot),**kwargs_ori)
|
|
||||||
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@util.extend_docstring(Rotation.from_Rodrigues_vector,
|
@util.extend_docstring(Rotation.from_Rodrigues_vector,
|
||||||
extra_parameters=_parameter_doc)
|
adopted_parameters=Crystal.__init__)
|
||||||
|
@util.pass_on('rotation', Rotation.from_Rodrigues_vector, wrapped=__init__)
|
||||||
def from_Rodrigues_vector(cls, **kwargs) -> 'Orientation':
|
def from_Rodrigues_vector(cls, **kwargs) -> 'Orientation':
|
||||||
kwargs_rot,kwargs_ori = Orientation._split_kwargs(kwargs,Rotation.from_Rodrigues_vector)
|
return cls(**kwargs)
|
||||||
return cls(rotation=Rotation.from_Rodrigues_vector(**kwargs_rot),**kwargs_ori)
|
|
||||||
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@util.extend_docstring(Rotation.from_homochoric,
|
@util.extend_docstring(Rotation.from_homochoric,
|
||||||
extra_parameters=_parameter_doc)
|
adopted_parameters=Crystal.__init__)
|
||||||
|
@util.pass_on('rotation', Rotation.from_homochoric, wrapped=__init__)
|
||||||
def from_homochoric(cls, **kwargs) -> 'Orientation':
|
def from_homochoric(cls, **kwargs) -> 'Orientation':
|
||||||
kwargs_rot,kwargs_ori = Orientation._split_kwargs(kwargs,Rotation.from_homochoric)
|
return cls(**kwargs)
|
||||||
return cls(rotation=Rotation.from_homochoric(**kwargs_rot),**kwargs_ori)
|
|
||||||
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@util.extend_docstring(Rotation.from_cubochoric,
|
@util.extend_docstring(Rotation.from_cubochoric,
|
||||||
extra_parameters=_parameter_doc)
|
adopted_parameters=Crystal.__init__)
|
||||||
|
@util.pass_on('rotation', Rotation.from_cubochoric, wrapped=__init__)
|
||||||
def from_cubochoric(cls, **kwargs) -> 'Orientation':
|
def from_cubochoric(cls, **kwargs) -> 'Orientation':
|
||||||
kwargs_rot,kwargs_ori = Orientation._split_kwargs(kwargs,Rotation.from_cubochoric)
|
return cls(**kwargs)
|
||||||
return cls(rotation=Rotation.from_cubochoric(**kwargs_rot),**kwargs_ori)
|
|
||||||
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@util.extend_docstring(Rotation.from_spherical_component,
|
@util.extend_docstring(Rotation.from_spherical_component,
|
||||||
extra_parameters=_parameter_doc)
|
adopted_parameters=Crystal.__init__)
|
||||||
|
@util.pass_on('rotation', Rotation.from_spherical_component, wrapped=__init__)
|
||||||
def from_spherical_component(cls, **kwargs) -> 'Orientation':
|
def from_spherical_component(cls, **kwargs) -> 'Orientation':
|
||||||
kwargs_rot,kwargs_ori = Orientation._split_kwargs(kwargs,Rotation.from_spherical_component)
|
return cls(**kwargs)
|
||||||
return cls(rotation=Rotation.from_spherical_component(**kwargs_rot),**kwargs_ori)
|
|
||||||
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@util.extend_docstring(Rotation.from_fiber_component,
|
@util.extend_docstring(Rotation.from_fiber_component,
|
||||||
extra_parameters=_parameter_doc)
|
adopted_parameters=Crystal.__init__)
|
||||||
|
@util.pass_on('rotation', Rotation.from_fiber_component, wrapped=__init__)
|
||||||
def from_fiber_component(cls, **kwargs) -> 'Orientation':
|
def from_fiber_component(cls, **kwargs) -> 'Orientation':
|
||||||
kwargs_rot,kwargs_ori = Orientation._split_kwargs(kwargs,Rotation.from_fiber_component)
|
return cls(**kwargs)
|
||||||
return cls(rotation=Rotation.from_fiber_component(**kwargs_rot),**kwargs_ori)
|
|
||||||
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@util.extend_docstring(extra_parameters=_parameter_doc)
|
@util.extend_docstring(adopted_parameters=Crystal.__init__)
|
||||||
def from_directions(cls,
|
def from_directions(cls,
|
||||||
uvw: FloatSequence,
|
uvw: FloatSequence,
|
||||||
hkl: FloatSequence,
|
hkl: FloatSequence,
|
||||||
|
@ -467,24 +398,24 @@ class Orientation(Rotation,Crystal):
|
||||||
if self.family == 'cubic':
|
if self.family == 'cubic':
|
||||||
return (np.prod(np.sqrt(2)-1. >= rho_abs,axis=-1) *
|
return (np.prod(np.sqrt(2)-1. >= rho_abs,axis=-1) *
|
||||||
(1. >= np.sum(rho_abs,axis=-1))).astype(bool)
|
(1. >= np.sum(rho_abs,axis=-1))).astype(bool)
|
||||||
elif self.family == 'hexagonal':
|
if self.family == 'hexagonal':
|
||||||
return (np.prod(1. >= rho_abs,axis=-1) *
|
return (np.prod(1. >= rho_abs,axis=-1) *
|
||||||
(2. >= np.sqrt(3)*rho_abs[...,0] + rho_abs[...,1]) *
|
(2. >= np.sqrt(3)*rho_abs[...,0] + rho_abs[...,1]) *
|
||||||
(2. >= np.sqrt(3)*rho_abs[...,1] + rho_abs[...,0]) *
|
(2. >= np.sqrt(3)*rho_abs[...,1] + rho_abs[...,0]) *
|
||||||
(2. >= np.sqrt(3) + rho_abs[...,2])).astype(bool)
|
(2. >= np.sqrt(3) + rho_abs[...,2])).astype(bool)
|
||||||
elif self.family == 'tetragonal':
|
if self.family == 'tetragonal':
|
||||||
return (np.prod(1. >= rho_abs[...,:2],axis=-1) *
|
return (np.prod(1. >= rho_abs[...,:2],axis=-1) *
|
||||||
(np.sqrt(2) >= rho_abs[...,0] + rho_abs[...,1]) *
|
(np.sqrt(2) >= rho_abs[...,0] + rho_abs[...,1]) *
|
||||||
(np.sqrt(2) >= rho_abs[...,2] + 1.)).astype(bool)
|
(np.sqrt(2) >= rho_abs[...,2] + 1.)).astype(bool)
|
||||||
elif self.family == 'orthorhombic':
|
if self.family == 'orthorhombic':
|
||||||
return (np.prod(1. >= rho_abs,axis=-1)).astype(bool)
|
return (np.prod(1. >= rho_abs,axis=-1)).astype(bool)
|
||||||
elif self.family == 'monoclinic':
|
if self.family == 'monoclinic':
|
||||||
return np.logical_or( 1. >= rho_abs[...,1],
|
return np.logical_or( 1. >= rho_abs[...,1],
|
||||||
np.isnan(rho_abs[...,1]))
|
np.isnan(rho_abs[...,1]))
|
||||||
elif self.family == 'triclinic':
|
if self.family == 'triclinic':
|
||||||
return np.ones(rho_abs.shape[:-1]).astype(bool)
|
return np.ones(rho_abs.shape[:-1]).astype(bool)
|
||||||
else:
|
|
||||||
raise TypeError(f'unknown symmetry "{self.family}"')
|
raise TypeError(f'unknown symmetry "{self.family}"')
|
||||||
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
@ -510,38 +441,40 @@ class Orientation(Rotation,Crystal):
|
||||||
return ((rho[...,0] >= rho[...,1]) &
|
return ((rho[...,0] >= rho[...,1]) &
|
||||||
(rho[...,1] >= rho[...,2]) &
|
(rho[...,1] >= rho[...,2]) &
|
||||||
(rho[...,2] >= 0)).astype(bool)
|
(rho[...,2] >= 0)).astype(bool)
|
||||||
elif self.family == 'hexagonal':
|
if self.family == 'hexagonal':
|
||||||
return ((rho[...,0] >= rho[...,1]*np.sqrt(3)) &
|
return ((rho[...,0] >= rho[...,1]*np.sqrt(3)) &
|
||||||
(rho[...,1] >= 0) &
|
(rho[...,1] >= 0) &
|
||||||
(rho[...,2] >= 0)).astype(bool)
|
(rho[...,2] >= 0)).astype(bool)
|
||||||
elif self.family == 'tetragonal':
|
if self.family == 'tetragonal':
|
||||||
return ((rho[...,0] >= rho[...,1]) &
|
return ((rho[...,0] >= rho[...,1]) &
|
||||||
(rho[...,1] >= 0) &
|
(rho[...,1] >= 0) &
|
||||||
(rho[...,2] >= 0)).astype(bool)
|
(rho[...,2] >= 0)).astype(bool)
|
||||||
elif self.family == 'orthorhombic':
|
if self.family == 'orthorhombic':
|
||||||
return ((rho[...,0] >= 0) &
|
return ((rho[...,0] >= 0) &
|
||||||
(rho[...,1] >= 0) &
|
(rho[...,1] >= 0) &
|
||||||
(rho[...,2] >= 0)).astype(bool)
|
(rho[...,2] >= 0)).astype(bool)
|
||||||
elif self.family == 'monoclinic':
|
if self.family == 'monoclinic':
|
||||||
return ((rho[...,1] >= 0) &
|
return ((rho[...,1] >= 0) &
|
||||||
(rho[...,2] >= 0)).astype(bool)
|
(rho[...,2] >= 0)).astype(bool)
|
||||||
else:
|
|
||||||
return np.ones_like(rho[...,0],dtype=bool)
|
return np.ones_like(rho[...,0],dtype=bool)
|
||||||
|
|
||||||
def disorientation(self,
|
def disorientation(self,
|
||||||
other: 'Orientation',
|
other: 'Orientation',
|
||||||
return_operators: bool = False) -> object:
|
return_operators: bool = False) -> object:
|
||||||
"""
|
"""
|
||||||
Calculate disorientation between myself and given other orientation.
|
Calculate disorientation between self and given other orientation.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
other : Orientation
|
other : Orientation
|
||||||
Orientation to calculate disorientation for.
|
Orientation to calculate disorientation for.
|
||||||
Shape of other blends with shape of own rotation array.
|
Shape of other blends with shape of own rotation array.
|
||||||
For example, shapes of (2,3) for own rotations and (3,2) for other's result in (2,3,2) disorientations.
|
For example, shapes of (2,3) for own rotations
|
||||||
|
and (3,2) for other's result in (2,3,2) disorientations.
|
||||||
return_operators : bool, optional
|
return_operators : bool, optional
|
||||||
Return index pair of symmetrically equivalent orientations that result in disorientation axis falling into FZ.
|
Return index pair of symmetrically equivalent orientations
|
||||||
|
that result in disorientation axis falling into FZ.
|
||||||
Defaults to False.
|
Defaults to False.
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
|
@ -578,8 +511,8 @@ class Orientation(Rotation,Crystal):
|
||||||
>>> N = 10000
|
>>> N = 10000
|
||||||
>>> a = damask.Orientation.from_random(shape=N,family='cubic')
|
>>> a = damask.Orientation.from_random(shape=N,family='cubic')
|
||||||
>>> b = damask.Orientation.from_random(shape=N,family='cubic')
|
>>> b = damask.Orientation.from_random(shape=N,family='cubic')
|
||||||
>>> d = a.disorientation(b).as_axis_angle(degrees=True,pair=True)[1]
|
>>> n,omega = a.disorientation(b).as_axis_angle(degrees=True,pair=True)
|
||||||
>>> plt.hist(d,25)
|
>>> plt.hist(omega,25)
|
||||||
>>> plt.show()
|
>>> plt.show()
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
@ -626,6 +559,7 @@ class Orientation(Rotation,Crystal):
|
||||||
----------
|
----------
|
||||||
weights : numpy.ndarray, shape (self.shape), optional
|
weights : numpy.ndarray, shape (self.shape), optional
|
||||||
Relative weights of orientations.
|
Relative weights of orientations.
|
||||||
|
Defaults to equal weights.
|
||||||
return_cloud : bool, optional
|
return_cloud : bool, optional
|
||||||
Return the specific (symmetrically equivalent) orientations that were averaged.
|
Return the specific (symmetrically equivalent) orientations that were averaged.
|
||||||
Defaults to False.
|
Defaults to False.
|
||||||
|
@ -895,8 +829,8 @@ class Orientation(Rotation,Crystal):
|
||||||
Schmid matrix (in lab frame) of first octahedral slip system of a face-centered
|
Schmid matrix (in lab frame) of first octahedral slip system of a face-centered
|
||||||
cubic crystal in "Goss" orientation.
|
cubic crystal in "Goss" orientation.
|
||||||
|
|
||||||
>>> import damask
|
|
||||||
>>> import numpy as np
|
>>> import numpy as np
|
||||||
|
>>> import damask
|
||||||
>>> np.set_printoptions(3,suppress=True,floatmode='fixed')
|
>>> np.set_printoptions(3,suppress=True,floatmode='fixed')
|
||||||
>>> O = damask.Orientation.from_Euler_angles(phi=[0,45,0],degrees=True,lattice='cF')
|
>>> O = damask.Orientation.from_Euler_angles(phi=[0,45,0],degrees=True,lattice='cF')
|
||||||
>>> O.Schmid(N_slip=[1])
|
>>> O.Schmid(N_slip=[1])
|
||||||
|
@ -936,8 +870,9 @@ class Orientation(Rotation,Crystal):
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
-------
|
-------
|
||||||
Orientations related to self following the selected
|
rel : Orientation, shape (:,self.shape)
|
||||||
model for the orientation relationship.
|
Orientations related to self according to the selected
|
||||||
|
model for the orientation relationship.
|
||||||
|
|
||||||
Examples
|
Examples
|
||||||
--------
|
--------
|
||||||
|
|
|
@ -15,7 +15,7 @@ from typing import Optional, Union, Callable, Any, Sequence, Literal, Dict, List
|
||||||
|
|
||||||
import h5py
|
import h5py
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import numpy.ma as ma
|
from numpy import ma
|
||||||
|
|
||||||
import damask
|
import damask
|
||||||
from . import VTK
|
from . import VTK
|
||||||
|
@ -65,9 +65,9 @@ def _empty_like(dataset: np.ma.core.MaskedArray,
|
||||||
|
|
||||||
class Result:
|
class Result:
|
||||||
"""
|
"""
|
||||||
Add data to and export data from a DADF5 file.
|
Add data to and export data from a DADF5 (DAMASK HDF5) file.
|
||||||
|
|
||||||
A DADF5 (DAMASK HDF5) file contains DAMASK results.
|
A DADF5 file contains DAMASK results.
|
||||||
Its group/folder structure reflects the layout in material.yaml.
|
Its group/folder structure reflects the layout in material.yaml.
|
||||||
|
|
||||||
This class provides a customizable view on the DADF5 file.
|
This class provides a customizable view on the DADF5 file.
|
||||||
|
@ -93,7 +93,7 @@ class Result:
|
||||||
|
|
||||||
def __init__(self, fname: Union[str, Path]):
|
def __init__(self, fname: Union[str, Path]):
|
||||||
"""
|
"""
|
||||||
New result view bound to a HDF5 file.
|
New result view bound to a DADF5 file.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
|
@ -106,10 +106,8 @@ class Result:
|
||||||
self.version_major = f.attrs['DADF5_version_major']
|
self.version_major = f.attrs['DADF5_version_major']
|
||||||
self.version_minor = f.attrs['DADF5_version_minor']
|
self.version_minor = f.attrs['DADF5_version_minor']
|
||||||
|
|
||||||
if self.version_major != 0 or not 12 <= self.version_minor <= 14:
|
if (self.version_major != 0 or not 14 <= self.version_minor <= 14) and self.version_major != 1:
|
||||||
raise TypeError(f'unsupported DADF5 version "{self.version_major}.{self.version_minor}"')
|
raise TypeError(f'unsupported DADF5 version "{self.version_major}.{self.version_minor}"')
|
||||||
if self.version_major == 0 and self.version_minor < 14:
|
|
||||||
self.export_simulation_setup = None # type: ignore
|
|
||||||
|
|
||||||
self.structured = 'cells' in f['geometry'].attrs.keys()
|
self.structured = 'cells' in f['geometry'].attrs.keys()
|
||||||
|
|
||||||
|
@ -167,7 +165,7 @@ class Result:
|
||||||
"""
|
"""
|
||||||
Return repr(self).
|
Return repr(self).
|
||||||
|
|
||||||
Give short human-readable summary.
|
Give short, human-readable summary.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
with h5py.File(self.fname,'r') as f:
|
with h5py.File(self.fname,'r') as f:
|
||||||
|
@ -195,7 +193,7 @@ class Result:
|
||||||
homogenizations: Union[None, str, Sequence[str], bool] = None,
|
homogenizations: Union[None, str, Sequence[str], bool] = None,
|
||||||
fields: Union[None, str, Sequence[str], bool] = None) -> "Result":
|
fields: Union[None, str, Sequence[str], bool] = None) -> "Result":
|
||||||
"""
|
"""
|
||||||
Manages the visibility of the groups.
|
Manage the visibility of the groups.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
|
@ -319,15 +317,15 @@ class Result:
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
increments: (list of) int, (list of) str, or bool, optional.
|
increments: (list of) int, (list of) str, or bool, optional.
|
||||||
Number(s) of increments to select.
|
Numbers of increments to select.
|
||||||
times: (list of) float, (list of) str, or bool, optional.
|
times: (list of) float, (list of) str, or bool, optional.
|
||||||
Simulation time(s) of increments to select.
|
Simulation times of increments to select.
|
||||||
phases: (list of) str, or bool, optional.
|
phases: (list of) str, or bool, optional.
|
||||||
Name(s) of phases to select.
|
Names of phases to select.
|
||||||
homogenizations: (list of) str, or bool, optional.
|
homogenizations: (list of) str, or bool, optional.
|
||||||
Name(s) of homogenizations to select.
|
Names of homogenizations to select.
|
||||||
fields: (list of) str, or bool, optional.
|
fields: (list of) str, or bool, optional.
|
||||||
Name(s) of fields to select.
|
Names of fields to select.
|
||||||
protected: bool, optional.
|
protected: bool, optional.
|
||||||
Protection status of existing data.
|
Protection status of existing data.
|
||||||
|
|
||||||
|
@ -375,15 +373,15 @@ class Result:
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
increments: (list of) int, (list of) str, or bool, optional.
|
increments: (list of) int, (list of) str, or bool, optional.
|
||||||
Number(s) of increments to select.
|
Numbers of increments to select.
|
||||||
times: (list of) float, (list of) str, or bool, optional.
|
times: (list of) float, (list of) str, or bool, optional.
|
||||||
Simulation time(s) of increments to select.
|
Simulation times of increments to select.
|
||||||
phases: (list of) str, or bool, optional.
|
phases: (list of) str, or bool, optional.
|
||||||
Name(s) of phases to select.
|
Names of phases to select.
|
||||||
homogenizations: (list of) str, or bool, optional.
|
homogenizations: (list of) str, or bool, optional.
|
||||||
Name(s) of homogenizations to select.
|
Names of homogenizations to select.
|
||||||
fields: (list of) str, or bool, optional.
|
fields: (list of) str, or bool, optional.
|
||||||
Name(s) of fields to select.
|
Names of fields to select.
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
-------
|
-------
|
||||||
|
@ -418,15 +416,15 @@ class Result:
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
increments: (list of) int, (list of) str, or bool, optional.
|
increments: (list of) int, (list of) str, or bool, optional.
|
||||||
Number(s) of increments to select.
|
Numbers of increments to select.
|
||||||
times: (list of) float, (list of) str, or bool, optional.
|
times: (list of) float, (list of) str, or bool, optional.
|
||||||
Simulation time(s) of increments to select.
|
Simulation times of increments to select.
|
||||||
phases: (list of) str, or bool, optional.
|
phases: (list of) str, or bool, optional.
|
||||||
Name(s) of phases to select.
|
Names of phases to select.
|
||||||
homogenizations: (list of) str, or bool, optional.
|
homogenizations: (list of) str, or bool, optional.
|
||||||
Name(s) of homogenizations to select.
|
Names of homogenizations to select.
|
||||||
fields: (list of) str, or bool, optional.
|
fields: (list of) str, or bool, optional.
|
||||||
Name(s) of fields to select.
|
Names of fields to select.
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
-------
|
-------
|
||||||
|
@ -678,7 +676,7 @@ class Result:
|
||||||
... '1/m²','total mobile dislocation density')
|
... '1/m²','total mobile dislocation density')
|
||||||
>>> r.add_calculation('np.sum(#rho_dip#,axis=1)','rho_dip_total',
|
>>> r.add_calculation('np.sum(#rho_dip#,axis=1)','rho_dip_total',
|
||||||
... '1/m²','total dislocation dipole density')
|
... '1/m²','total dislocation dipole density')
|
||||||
>>> r.add_calculation('#rho_dip_total#+#rho_mob_total','rho_total',
|
>>> r.add_calculation('#rho_dip_total#+#rho_mob_total#','rho_total',
|
||||||
... '1/m²','total dislocation density')
|
... '1/m²','total dislocation density')
|
||||||
|
|
||||||
Add Mises equivalent of the Cauchy stress without storage of
|
Add Mises equivalent of the Cauchy stress without storage of
|
||||||
|
@ -721,9 +719,11 @@ class Result:
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
P : str, optional
|
P : str, optional
|
||||||
Name of the dataset containing the first Piola-Kirchhoff stress. Defaults to 'P'.
|
Name of the dataset containing the first Piola-Kirchhoff stress.
|
||||||
|
Defaults to 'P'.
|
||||||
F : str, optional
|
F : str, optional
|
||||||
Name of the dataset containing the deformation gradient. Defaults to 'F'.
|
Name of the dataset containing the deformation gradient.
|
||||||
|
Defaults to 'F'.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
self._add_generic_pointwise(self._add_stress_Cauchy,{'P':P,'F':F})
|
self._add_generic_pointwise(self._add_stress_Cauchy,{'P':P,'F':F})
|
||||||
|
@ -1023,14 +1023,14 @@ class Result:
|
||||||
x: str,
|
x: str,
|
||||||
ord: Union[None, int, float, Literal['fro', 'nuc']] = None):
|
ord: Union[None, int, float, Literal['fro', 'nuc']] = None):
|
||||||
"""
|
"""
|
||||||
Add the norm of vector or tensor.
|
Add the norm of a vector or tensor.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
x : str
|
x : str
|
||||||
Name of vector or tensor dataset.
|
Name of vector or tensor dataset.
|
||||||
ord : {non-zero int, inf, -inf, 'fro', 'nuc'}, optional
|
ord : {non-zero int, inf, -inf, 'fro', 'nuc'}, optional
|
||||||
Order of the norm. inf means NumPy’s inf object. For details refer to numpy.linalg.norm.
|
Order of the norm. inf means NumPy's inf object. For details refer to numpy.linalg.norm.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
self._add_generic_pointwise(self._add_norm,{'x':x},{'ord':ord})
|
self._add_generic_pointwise(self._add_norm,{'x':x},{'ord':ord})
|
||||||
|
@ -1052,7 +1052,7 @@ class Result:
|
||||||
def add_stress_second_Piola_Kirchhoff(self,
|
def add_stress_second_Piola_Kirchhoff(self,
|
||||||
P: str = 'P',
|
P: str = 'P',
|
||||||
F: str = 'F'):
|
F: str = 'F'):
|
||||||
"""
|
r"""
|
||||||
Add second Piola-Kirchhoff stress calculated from first Piola-Kirchhoff stress and deformation gradient.
|
Add second Piola-Kirchhoff stress calculated from first Piola-Kirchhoff stress and deformation gradient.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
|
@ -1064,9 +1064,10 @@ class Result:
|
||||||
|
|
||||||
Notes
|
Notes
|
||||||
-----
|
-----
|
||||||
The definition of the second Piola-Kirchhoff stress (S = [F^-1 P]_sym)
|
The definition of the second Piola-Kirchhoff stress
|
||||||
|
:math:`\vb{S} = \left(\vb{F}^{-1} \vb{P}\right)_\text{sym}`
|
||||||
follows the standard definition in nonlinear continuum mechanics.
|
follows the standard definition in nonlinear continuum mechanics.
|
||||||
As such, no intermediate configuration, for instance that reached by F_p,
|
As such, no intermediate configuration, for instance that reached by :math:`\vb{F}_\text{p}`,
|
||||||
is taken into account.
|
is taken into account.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
@ -1240,10 +1241,11 @@ class Result:
|
||||||
|
|
||||||
Notes
|
Notes
|
||||||
-----
|
-----
|
||||||
The incoporation of rotational parts into the elastic and plastic
|
The presence of rotational parts in the elastic and plastic deformation gradient
|
||||||
deformation gradient requires it to use material/Lagragian strain measures
|
calls for the use of
|
||||||
(based on 'U') for plastic strains and spatial/Eulerian strain measures
|
material/Lagragian strain measures (based on 'U') for plastic strains and
|
||||||
(based on 'V') for elastic strains when calculating averages.
|
spatial/Eulerian strain measures (based on 'V') for elastic strains
|
||||||
|
when calculating averages.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
self._add_generic_pointwise(self._add_strain,{'F':F},{'t':t,'m':m})
|
self._add_generic_pointwise(self._add_strain,{'F':F},{'t':t,'m':m})
|
||||||
|
@ -1302,7 +1304,7 @@ class Result:
|
||||||
Notes
|
Notes
|
||||||
-----
|
-----
|
||||||
This function is only available for structured grids,
|
This function is only available for structured grids,
|
||||||
i.e. results from the grid solver.
|
i.e. fields resulting from the grid solver.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
self._add_generic_grid(self._add_curl,{'f':f},{'size':self.size})
|
self._add_generic_grid(self._add_curl,{'f':f},{'size':self.size})
|
||||||
|
@ -1331,7 +1333,7 @@ class Result:
|
||||||
Notes
|
Notes
|
||||||
-----
|
-----
|
||||||
This function is only available for structured grids,
|
This function is only available for structured grids,
|
||||||
i.e. results from the grid solver.
|
i.e. fields resulting from the grid solver.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
self._add_generic_grid(self._add_divergence,{'f':f},{'size':self.size})
|
self._add_generic_grid(self._add_divergence,{'f':f},{'size':self.size})
|
||||||
|
@ -1361,7 +1363,7 @@ class Result:
|
||||||
Notes
|
Notes
|
||||||
-----
|
-----
|
||||||
This function is only available for structured grids,
|
This function is only available for structured grids,
|
||||||
i.e. results from the grid solver.
|
i.e. fields resulting from the grid solver.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
self._add_generic_grid(self._add_gradient,{'f':f},{'size':self.size})
|
self._add_generic_grid(self._add_gradient,{'f':f},{'size':self.size})
|
||||||
|
@ -1379,10 +1381,10 @@ class Result:
|
||||||
----------
|
----------
|
||||||
func : function
|
func : function
|
||||||
Callback function that calculates a new dataset from one or
|
Callback function that calculates a new dataset from one or
|
||||||
more datasets per HDF5 group.
|
more datasets per DADF5 group.
|
||||||
datasets : dictionary
|
datasets : dictionary
|
||||||
Details of the datasets to be used:
|
Details of the datasets to be used:
|
||||||
{arg (name to which the data is passed in func): label (in HDF5 file)}.
|
{arg (name to which the data is passed in func): label (in DADF5 file)}.
|
||||||
args : dictionary, optional
|
args : dictionary, optional
|
||||||
Arguments parsed to func.
|
Arguments parsed to func.
|
||||||
|
|
||||||
|
@ -1462,10 +1464,10 @@ class Result:
|
||||||
----------
|
----------
|
||||||
callback : function
|
callback : function
|
||||||
Callback function that calculates a new dataset from one or
|
Callback function that calculates a new dataset from one or
|
||||||
more datasets per HDF5 group.
|
more datasets per DADF5 group.
|
||||||
datasets : dictionary
|
datasets : dictionary
|
||||||
Details of the datasets to be used:
|
Details of the datasets to be used:
|
||||||
{arg (name to which the data is passed in func): label (in HDF5 file)}.
|
{arg (name to which the data is passed in func): label (in DADF5 file)}.
|
||||||
args : dictionary, optional
|
args : dictionary, optional
|
||||||
Arguments parsed to func.
|
Arguments parsed to func.
|
||||||
|
|
||||||
|
@ -1500,7 +1502,7 @@ class Result:
|
||||||
dataset.attrs['overwritten'] = True
|
dataset.attrs['overwritten'] = True
|
||||||
else:
|
else:
|
||||||
shape = result['data'].shape
|
shape = result['data'].shape
|
||||||
if compress := (result['data'].size >= chunk_size*2):
|
if compress := result['data'].size >= chunk_size*2:
|
||||||
chunks = (chunk_size//np.prod(shape[1:]),)+shape[1:]
|
chunks = (chunk_size//np.prod(shape[1:]),)+shape[1:]
|
||||||
else:
|
else:
|
||||||
chunks = shape
|
chunks = shape
|
||||||
|
@ -1828,9 +1830,10 @@ class Result:
|
||||||
Export to VTK cell/point data.
|
Export to VTK cell/point data.
|
||||||
|
|
||||||
One VTK file per visible increment is created.
|
One VTK file per visible increment is created.
|
||||||
For point data, the VTK format is poly data (.vtp).
|
For point data, the VTK format is PolyData (.vtp).
|
||||||
For cell data, either an image (.vti) or unstructured (.vtu) dataset
|
For cell data, the file format is either ImageData (.vti)
|
||||||
is written for grid-based or mesh-based simulations, respectively.
|
or UnstructuredGrid (.vtu) for grid-based or mesh-based simulations,
|
||||||
|
respectively.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
|
@ -1922,7 +1925,8 @@ class Result:
|
||||||
|
|
||||||
def export_DADF5(self,
|
def export_DADF5(self,
|
||||||
fname,
|
fname,
|
||||||
output: Union[str, List[str]] = '*'):
|
output: Union[str, List[str]] = '*',
|
||||||
|
mapping = None):
|
||||||
"""
|
"""
|
||||||
Export visible components into a new DADF5 file.
|
Export visible components into a new DADF5 file.
|
||||||
|
|
||||||
|
@ -1936,20 +1940,61 @@ class Result:
|
||||||
output : (list of) str, optional
|
output : (list of) str, optional
|
||||||
Names of the datasets to export.
|
Names of the datasets to export.
|
||||||
Defaults to '*', in which case all visible datasets are exported.
|
Defaults to '*', in which case all visible datasets are exported.
|
||||||
|
mapping : numpy.ndarray of int, shape (:,:,:), optional
|
||||||
|
Indices for regridding.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if Path(fname).expanduser().absolute() == self.fname:
|
if Path(fname).expanduser().absolute() == self.fname:
|
||||||
raise PermissionError(f'cannot overwrite {self.fname}')
|
raise PermissionError(f'cannot overwrite {self.fname}')
|
||||||
|
|
||||||
|
def cp(path_in,path_out,label,mapping):
|
||||||
|
if mapping is None:
|
||||||
|
path_in.copy(label,path_out)
|
||||||
|
else:
|
||||||
|
path_out.create_dataset(label,data=path_in[label][()][mapping])
|
||||||
|
path_out[label].attrs.update(path_in[label].attrs)
|
||||||
|
|
||||||
|
|
||||||
with h5py.File(self.fname,'r') as f_in, h5py.File(fname,'w') as f_out:
|
with h5py.File(self.fname,'r') as f_in, h5py.File(fname,'w') as f_out:
|
||||||
for k,v in f_in.attrs.items():
|
f_out.attrs.update(f_in.attrs)
|
||||||
f_out.attrs.create(k,v)
|
for g in ['setup','geometry'] + (['cell_to'] if mapping is None else []):
|
||||||
for g in ['setup','geometry','cell_to']:
|
|
||||||
f_in.copy(g,f_out)
|
f_in.copy(g,f_out)
|
||||||
|
|
||||||
|
if mapping is not None:
|
||||||
|
cells = mapping.shape
|
||||||
|
mapping_flat = mapping.flatten(order='F')
|
||||||
|
f_out['geometry'].attrs['cells'] = cells
|
||||||
|
f_out.create_group('cell_to') # ToDo: attribute missing
|
||||||
|
mappings = {'phase':{},'homogenization':{}} # type: ignore
|
||||||
|
|
||||||
|
mapping_phase = f_in['cell_to']['phase'][()][mapping_flat]
|
||||||
|
for p in np.unique(mapping_phase['label']):
|
||||||
|
m = mapping_phase['label'] == p
|
||||||
|
mappings['phase'][p] = mapping_phase[m]['entry']
|
||||||
|
c = np.count_nonzero(m)
|
||||||
|
mapping_phase[m] = list(zip((p,)*c,tuple(np.arange(c))))
|
||||||
|
f_out['cell_to'].create_dataset('phase',data=mapping_phase.reshape(np.prod(mapping_flat.shape),-1))
|
||||||
|
|
||||||
|
mapping_homog = f_in['cell_to']['homogenization'][()][mapping]
|
||||||
|
for h in np.unique(mapping_homog['label']):
|
||||||
|
m = mapping_homog['label'] == h
|
||||||
|
mappings['homogenization'][h] = mapping_homog[m]['entry']
|
||||||
|
c = np.count_nonzero(m)
|
||||||
|
mapping_homog[mapping_homog['label'] == h] = list(zip((h,)*c,tuple(np.arange(c))))
|
||||||
|
f_out['cell_to'].create_dataset('homogenization',data=mapping_homog.flatten())
|
||||||
|
|
||||||
|
|
||||||
for inc in util.show_progress(self.visible['increments']):
|
for inc in util.show_progress(self.visible['increments']):
|
||||||
f_in.copy(inc,f_out,shallow=True)
|
f_in.copy(inc,f_out,shallow=True)
|
||||||
for out in _match(output,f_in['/'.join([inc,'geometry'])].keys()):
|
if mapping is None:
|
||||||
f_in[inc]['geometry'].copy(out,f_out[inc]['geometry'])
|
for label in ['u_p','u_n']:
|
||||||
|
f_in[inc]['geometry'].copy(label,f_out[inc]['geometry'])
|
||||||
|
else:
|
||||||
|
u_p = f_in[inc]['geometry']['u_p'][()][mapping_flat]
|
||||||
|
f_out[inc]['geometry'].create_dataset('u_p',data=u_p)
|
||||||
|
u_n = np.zeros((len(mapping_flat),3)) # ToDo: needs implementation
|
||||||
|
f_out[inc]['geometry'].create_dataset('u_n',data=u_n)
|
||||||
|
|
||||||
|
|
||||||
for label in self.homogenizations:
|
for label in self.homogenizations:
|
||||||
f_in[inc]['homogenization'].copy(label,f_out[inc]['homogenization'],shallow=True)
|
f_in[inc]['homogenization'].copy(label,f_out[inc]['homogenization'],shallow=True)
|
||||||
|
@ -1961,7 +2006,7 @@ class Result:
|
||||||
for field in _match(self.visible['fields'],f_in['/'.join([inc,ty,label])].keys()):
|
for field in _match(self.visible['fields'],f_in['/'.join([inc,ty,label])].keys()):
|
||||||
p = '/'.join([inc,ty,label,field])
|
p = '/'.join([inc,ty,label,field])
|
||||||
for out in _match(output,f_in[p].keys()):
|
for out in _match(output,f_in[p].keys()):
|
||||||
f_in[p].copy(out,f_out[p])
|
cp(f_in[p],f_out[p],out,None if mapping is None else mappings[ty][label.encode()])
|
||||||
|
|
||||||
|
|
||||||
def export_simulation_setup(self,
|
def export_simulation_setup(self,
|
||||||
|
|
|
@ -35,8 +35,8 @@ class Rotation:
|
||||||
Rotate vector 'a' (defined in coordinate system 'A') to
|
Rotate vector 'a' (defined in coordinate system 'A') to
|
||||||
coordinates 'b' expressed in system 'B':
|
coordinates 'b' expressed in system 'B':
|
||||||
|
|
||||||
>>> import damask
|
|
||||||
>>> import numpy as np
|
>>> import numpy as np
|
||||||
|
>>> import damask
|
||||||
>>> Q = damask.Rotation.from_random()
|
>>> Q = damask.Rotation.from_random()
|
||||||
>>> a = np.random.rand(3)
|
>>> a = np.random.rand(3)
|
||||||
>>> b = Q @ a
|
>>> b = Q @ a
|
||||||
|
@ -45,8 +45,8 @@ class Rotation:
|
||||||
|
|
||||||
Compound rotations R1 (first) and R2 (second):
|
Compound rotations R1 (first) and R2 (second):
|
||||||
|
|
||||||
>>> import damask
|
|
||||||
>>> import numpy as np
|
>>> import numpy as np
|
||||||
|
>>> import damask
|
||||||
>>> R1 = damask.Rotation.from_random()
|
>>> R1 = damask.Rotation.from_random()
|
||||||
>>> R2 = damask.Rotation.from_random()
|
>>> R2 = damask.Rotation.from_random()
|
||||||
>>> R = R2 * R1
|
>>> R = R2 * R1
|
||||||
|
@ -69,7 +69,7 @@ class Rotation:
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
rotation : list, numpy.ndarray, Rotation, optional
|
rotation : list, numpy.ndarray, or Rotation, optional
|
||||||
Unit quaternion in positive real hemisphere.
|
Unit quaternion in positive real hemisphere.
|
||||||
Use .from_quaternion to perform a sanity check.
|
Use .from_quaternion to perform a sanity check.
|
||||||
Defaults to no rotation.
|
Defaults to no rotation.
|
||||||
|
@ -88,7 +88,7 @@ class Rotation:
|
||||||
"""
|
"""
|
||||||
Return repr(self).
|
Return repr(self).
|
||||||
|
|
||||||
Give short human-readable summary.
|
Give short, human-readable summary.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
return f'Quaternion{" " if self.quaternion.shape == (4,) else "s of shape "+str(self.quaternion.shape[:-1])+chr(10)}'\
|
return f'Quaternion{" " if self.quaternion.shape == (4,) else "s of shape "+str(self.quaternion.shape[:-1])+chr(10)}'\
|
||||||
|
@ -902,7 +902,8 @@ class Rotation:
|
||||||
return Rotation(Rotation._om2qu(om))
|
return Rotation(Rotation._om2qu(om))
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def from_matrix(R: np.ndarray) -> 'Rotation':
|
def from_matrix(R: np.ndarray,
|
||||||
|
normalize: bool = False) -> 'Rotation':
|
||||||
"""
|
"""
|
||||||
Initialize from rotation matrix.
|
Initialize from rotation matrix.
|
||||||
|
|
||||||
|
@ -910,13 +911,17 @@ class Rotation:
|
||||||
----------
|
----------
|
||||||
R : numpy.ndarray, shape (...,3,3)
|
R : numpy.ndarray, shape (...,3,3)
|
||||||
Rotation matrix with det(R) = 1 and R.T ∙ R = I.
|
Rotation matrix with det(R) = 1 and R.T ∙ R = I.
|
||||||
|
normalize : bool, optional
|
||||||
|
Rescales rotation matrix to unit determinant. Defaults to False.
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
-------
|
-------
|
||||||
new : damask.Rotation
|
new : damask.Rotation
|
||||||
|
|
||||||
"""
|
"""
|
||||||
return Rotation.from_basis(R)
|
return Rotation.from_basis(np.array(R,dtype=float) * (np.linalg.det(R)**(-1./3.))[...,np.newaxis,np.newaxis]
|
||||||
|
if normalize else
|
||||||
|
R)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def from_parallel(a: np.ndarray,
|
def from_parallel(a: np.ndarray,
|
||||||
|
|
|
@ -41,7 +41,7 @@ class Table:
|
||||||
"""
|
"""
|
||||||
Return repr(self).
|
Return repr(self).
|
||||||
|
|
||||||
Give short human-readable summary.
|
Give short, human-readable summary.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
self._relabel('shapes')
|
self._relabel('shapes')
|
||||||
|
@ -255,8 +255,8 @@ class Table:
|
||||||
"""
|
"""
|
||||||
Load from ASCII table file.
|
Load from ASCII table file.
|
||||||
|
|
||||||
Initial comments are marked by '#', the first non-comment line
|
Initial comments are marked by '#'.
|
||||||
containing the column labels.
|
The first non-comment line contains the column labels.
|
||||||
|
|
||||||
- Vector data column labels are indicated by '1_v, 2_v, ..., n_v'.
|
- Vector data column labels are indicated by '1_v, 2_v, ..., n_v'.
|
||||||
- Tensor data column labels are indicated by '3x3:1_T, 3x3:2_T, ..., 3x3:9_T'.
|
- Tensor data column labels are indicated by '3x3:1_T, 3x3:2_T, ..., 3x3:9_T'.
|
||||||
|
@ -264,7 +264,7 @@ class Table:
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
fname : file, str, or pathlib.Path
|
fname : file, str, or pathlib.Path
|
||||||
Filename or file for reading.
|
Filename or file to read.
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
-------
|
-------
|
||||||
|
@ -299,11 +299,18 @@ class Table:
|
||||||
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def load_ang(fname: FileHandle) -> 'Table':
|
def load_ang(fname: FileHandle,
|
||||||
|
shapes = {'eu':3,
|
||||||
|
'pos':2,
|
||||||
|
'IQ':1,
|
||||||
|
'CI':1,
|
||||||
|
'ID':1,
|
||||||
|
'intensity':1,
|
||||||
|
'fit':1}) -> 'Table':
|
||||||
"""
|
"""
|
||||||
Load from ang file.
|
Load from ANG file.
|
||||||
|
|
||||||
A valid TSL ang file has to have the following columns:
|
Regular ANG files feature the following columns:
|
||||||
|
|
||||||
- Euler angles (Bunge notation) in radians, 3 floats, label 'eu'.
|
- Euler angles (Bunge notation) in radians, 3 floats, label 'eu'.
|
||||||
- Spatial position in meters, 2 floats, label 'pos'.
|
- Spatial position in meters, 2 floats, label 'pos'.
|
||||||
|
@ -316,7 +323,10 @@ class Table:
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
fname : file, str, or pathlib.Path
|
fname : file, str, or pathlib.Path
|
||||||
Filename or file for reading.
|
Filename or file to read.
|
||||||
|
shapes : dict with str:int pairs, optional
|
||||||
|
Column labels and their width.
|
||||||
|
Defaults to standard TSL ANG format.
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
-------
|
-------
|
||||||
|
@ -338,7 +348,6 @@ class Table:
|
||||||
|
|
||||||
data = np.loadtxt(content)
|
data = np.loadtxt(content)
|
||||||
|
|
||||||
shapes = {'eu':3, 'pos':2, 'IQ':1, 'CI':1, 'ID':1, 'intensity':1, 'fit':1}
|
|
||||||
if (remainder := data.shape[1]-sum(shapes.values())) > 0:
|
if (remainder := data.shape[1]-sum(shapes.values())) > 0:
|
||||||
shapes['unknown'] = remainder
|
shapes['unknown'] = remainder
|
||||||
|
|
||||||
|
@ -458,9 +467,9 @@ class Table:
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
label_old : (iterable of) str
|
label_old : (iterable of) str
|
||||||
Old column label(s).
|
Old column labels.
|
||||||
label_new : (iterable of) str
|
label_new : (iterable of) str
|
||||||
New column label(s).
|
New column labels.
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
-------
|
-------
|
||||||
|
@ -488,7 +497,7 @@ class Table:
|
||||||
label : str or list
|
label : str or list
|
||||||
Column labels for sorting.
|
Column labels for sorting.
|
||||||
ascending : bool or list, optional
|
ascending : bool or list, optional
|
||||||
Set sort order.
|
Set sort order. Defaults to True.
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
-------
|
-------
|
||||||
|
@ -574,7 +583,7 @@ class Table:
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
fname : file, str, or pathlib.Path
|
fname : file, str, or pathlib.Path
|
||||||
Filename or file for writing.
|
Filename or file to write.
|
||||||
with_labels : bool, optional
|
with_labels : bool, optional
|
||||||
Write column labels. Defaults to True.
|
Write column labels. Defaults to True.
|
||||||
|
|
||||||
|
@ -594,4 +603,7 @@ class Table:
|
||||||
f = util.open_text(fname,'w')
|
f = util.open_text(fname,'w')
|
||||||
|
|
||||||
f.write('\n'.join([f'# {c}' for c in self.comments] + [' '.join(labels)])+('\n' if labels else ''))
|
f.write('\n'.join([f'# {c}' for c in self.comments] + [' '.join(labels)])+('\n' if labels else ''))
|
||||||
self.data.to_csv(f,sep=' ',na_rep='nan',index=False,header=False,line_terminator='\n')
|
try: # backward compatibility
|
||||||
|
self.data.to_csv(f,sep=' ',na_rep='nan',index=False,header=False,lineterminator='\n')
|
||||||
|
except TypeError:
|
||||||
|
self.data.to_csv(f,sep=' ',na_rep='nan',index=False,header=False,line_terminator='\n')
|
||||||
|
|
|
@ -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]]
|
||||||
|
StrSequence = Union[np.ndarray,Sequence[str]]
|
||||||
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']]
|
||||||
|
|
|
@ -4,10 +4,54 @@ from pathlib import Path
|
||||||
from typing import Optional, Union, Literal, List, Sequence
|
from typing import Optional, Union, Literal, List, Sequence
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import vtk
|
from vtkmodules.vtkCommonCore import (
|
||||||
from vtk.util.numpy_support import numpy_to_vtk as np_to_vtk
|
vtkPoints,
|
||||||
from vtk.util.numpy_support import numpy_to_vtkIdTypeArray as np_to_vtkIdTypeArray
|
vtkStringArray,
|
||||||
from vtk.util.numpy_support import vtk_to_numpy as vtk_to_np
|
vtkLookupTable,
|
||||||
|
)
|
||||||
|
from vtkmodules.vtkCommonDataModel import (
|
||||||
|
vtkDataSet,
|
||||||
|
vtkCellArray,
|
||||||
|
vtkImageData,
|
||||||
|
vtkRectilinearGrid,
|
||||||
|
vtkUnstructuredGrid,
|
||||||
|
vtkPolyData,
|
||||||
|
)
|
||||||
|
from vtkmodules.vtkIOLegacy import (
|
||||||
|
vtkGenericDataObjectReader,
|
||||||
|
vtkDataSetWriter,
|
||||||
|
)
|
||||||
|
from vtkmodules.vtkIOXML import (
|
||||||
|
vtkXMLImageDataReader,
|
||||||
|
vtkXMLImageDataWriter,
|
||||||
|
vtkXMLRectilinearGridReader,
|
||||||
|
vtkXMLRectilinearGridWriter,
|
||||||
|
vtkXMLUnstructuredGridReader,
|
||||||
|
vtkXMLUnstructuredGridWriter,
|
||||||
|
vtkXMLPolyDataReader,
|
||||||
|
vtkXMLPolyDataWriter,
|
||||||
|
)
|
||||||
|
from vtkmodules.vtkRenderingCore import (
|
||||||
|
vtkDataSetMapper,
|
||||||
|
vtkActor,
|
||||||
|
vtkRenderer,
|
||||||
|
vtkRenderWindow,
|
||||||
|
vtkRenderWindowInteractor,
|
||||||
|
)
|
||||||
|
from vtkmodules.vtkRenderingAnnotation import (
|
||||||
|
vtkScalarBarActor,
|
||||||
|
)
|
||||||
|
from vtkmodules.util.vtkConstants import (
|
||||||
|
VTK_TRIANGLE,
|
||||||
|
VTK_QUAD,
|
||||||
|
VTK_TETRA,
|
||||||
|
VTK_HEXAHEDRON,
|
||||||
|
)
|
||||||
|
from vtkmodules.util.numpy_support import (
|
||||||
|
numpy_to_vtk,
|
||||||
|
numpy_to_vtkIdTypeArray,
|
||||||
|
vtk_to_numpy,
|
||||||
|
)
|
||||||
|
|
||||||
from ._typehints import FloatSequence, IntSequence
|
from ._typehints import FloatSequence, IntSequence
|
||||||
from . import util
|
from . import util
|
||||||
|
@ -23,16 +67,16 @@ class VTK:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
vtk_data: vtk.vtkDataSet):
|
vtk_data: vtkDataSet):
|
||||||
"""
|
"""
|
||||||
New spatial visualization.
|
New spatial visualization.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
vtk_data : subclass of vtk.vtkDataSet
|
vtk_data : subclass of vtkDataSet
|
||||||
Description of geometry and topology, optionally with attached data.
|
Description of geometry and topology, optionally with attached data.
|
||||||
Valid types are vtk.vtkImageData, vtk.vtkUnstructuredGrid,
|
Valid types are vtkImageData, vtkUnstructuredGrid,
|
||||||
vtk.vtkPolyData, and vtk.vtkRectilinearGrid.
|
vtkPolyData, and vtkRectilinearGrid.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
self.vtk_data = vtk_data
|
self.vtk_data = vtk_data
|
||||||
|
@ -42,7 +86,7 @@ class VTK:
|
||||||
"""
|
"""
|
||||||
Return repr(self).
|
Return repr(self).
|
||||||
|
|
||||||
Give short human-readable summary.
|
Give short, human-readable summary.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
info = [self.vtk_data.__vtkname__]
|
info = [self.vtk_data.__vtkname__]
|
||||||
|
@ -76,14 +120,14 @@ class VTK:
|
||||||
|
|
||||||
|
|
||||||
def copy(self):
|
def copy(self):
|
||||||
if isinstance(self.vtk_data,vtk.vtkImageData):
|
if isinstance(self.vtk_data,vtkImageData):
|
||||||
dup = vtk.vtkImageData()
|
dup = vtkImageData()
|
||||||
elif isinstance(self.vtk_data,vtk.vtkUnstructuredGrid):
|
elif isinstance(self.vtk_data,vtkUnstructuredGrid):
|
||||||
dup = vtk.vtkUnstructuredGrid()
|
dup = vtkUnstructuredGrid()
|
||||||
elif isinstance(self.vtk_data,vtk.vtkPolyData):
|
elif isinstance(self.vtk_data,vtkPolyData):
|
||||||
dup = vtk.vtkPolyData()
|
dup = vtkPolyData()
|
||||||
elif isinstance(self.vtk_data,vtk.vtkRectilinearGrid):
|
elif isinstance(self.vtk_data,vtkRectilinearGrid):
|
||||||
dup = vtk.vtkRectilinearGrid()
|
dup = vtkRectilinearGrid()
|
||||||
else:
|
else:
|
||||||
raise TypeError
|
raise TypeError
|
||||||
|
|
||||||
|
@ -114,7 +158,7 @@ class VTK:
|
||||||
Comments.
|
Comments.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
s = vtk.vtkStringArray()
|
s = vtkStringArray()
|
||||||
s.SetName('comments')
|
s.SetName('comments')
|
||||||
for c in comments:
|
for c in comments:
|
||||||
s.InsertNextValue(c)
|
s.InsertNextValue(c)
|
||||||
|
@ -154,7 +198,7 @@ class VTK:
|
||||||
size: FloatSequence,
|
size: FloatSequence,
|
||||||
origin: FloatSequence = np.zeros(3)) -> 'VTK':
|
origin: FloatSequence = np.zeros(3)) -> 'VTK':
|
||||||
"""
|
"""
|
||||||
Create VTK of type vtk.vtkImageData.
|
Create VTK of type vtkImageData.
|
||||||
|
|
||||||
This is the common type for grid solver results.
|
This is the common type for grid solver results.
|
||||||
|
|
||||||
|
@ -163,7 +207,7 @@ class VTK:
|
||||||
cells : sequence of int, len (3)
|
cells : sequence of int, len (3)
|
||||||
Number of cells along each dimension.
|
Number of cells along each dimension.
|
||||||
size : sequence of float, len (3)
|
size : sequence of float, len (3)
|
||||||
Physical length along each dimension.
|
Edge length along each dimension.
|
||||||
origin : sequence of float, len (3), optional
|
origin : sequence of float, len (3), optional
|
||||||
Coordinates of grid origin.
|
Coordinates of grid origin.
|
||||||
|
|
||||||
|
@ -173,7 +217,7 @@ class VTK:
|
||||||
VTK-based geometry without nodal or cell data.
|
VTK-based geometry without nodal or cell data.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
vtk_data = vtk.vtkImageData()
|
vtk_data = vtkImageData()
|
||||||
vtk_data.SetDimensions(*(np.array(cells)+1))
|
vtk_data.SetDimensions(*(np.array(cells)+1))
|
||||||
vtk_data.SetOrigin(*(np.array(origin)))
|
vtk_data.SetOrigin(*(np.array(origin)))
|
||||||
vtk_data.SetSpacing(*(np.array(size)/np.array(cells)))
|
vtk_data.SetSpacing(*(np.array(size)/np.array(cells)))
|
||||||
|
@ -186,7 +230,7 @@ class VTK:
|
||||||
connectivity: np.ndarray,
|
connectivity: np.ndarray,
|
||||||
cell_type: str) -> 'VTK':
|
cell_type: str) -> 'VTK':
|
||||||
"""
|
"""
|
||||||
Create VTK of type vtk.vtkUnstructuredGrid.
|
Create VTK of type vtkUnstructuredGrid.
|
||||||
|
|
||||||
This is the common type for mesh solver results.
|
This is the common type for mesh solver results.
|
||||||
|
|
||||||
|
@ -198,7 +242,7 @@ class VTK:
|
||||||
Cell connectivity (0-based), first dimension determines #Cells,
|
Cell connectivity (0-based), first dimension determines #Cells,
|
||||||
second dimension determines #Nodes/Cell.
|
second dimension determines #Nodes/Cell.
|
||||||
cell_type : str
|
cell_type : str
|
||||||
Name of the vtk.vtkCell subclass. Tested for TRIANGLE, QUAD, TETRA, and HEXAHEDRON.
|
Name of the vtkCell subclass. Tested for TRIANGLE, QUAD, TETRA, and HEXAHEDRON.
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
-------
|
-------
|
||||||
|
@ -206,18 +250,18 @@ class VTK:
|
||||||
VTK-based geometry without nodal or cell data.
|
VTK-based geometry without nodal or cell data.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
vtk_nodes = vtk.vtkPoints()
|
vtk_nodes = vtkPoints()
|
||||||
vtk_nodes.SetData(np_to_vtk(np.ascontiguousarray(nodes)))
|
vtk_nodes.SetData(numpy_to_vtk(np.ascontiguousarray(nodes)))
|
||||||
cells = vtk.vtkCellArray()
|
cells = vtkCellArray()
|
||||||
cells.SetNumberOfCells(connectivity.shape[0])
|
cells.SetNumberOfCells(connectivity.shape[0])
|
||||||
T = np.concatenate((np.ones((connectivity.shape[0],1),dtype=np.int64)*connectivity.shape[1],
|
T = np.concatenate((np.ones((connectivity.shape[0],1),dtype=np.int64)*connectivity.shape[1],
|
||||||
connectivity),axis=1).ravel()
|
connectivity),axis=1).ravel()
|
||||||
cells.SetCells(connectivity.shape[0],np_to_vtkIdTypeArray(T,deep=True))
|
cells.SetCells(connectivity.shape[0],numpy_to_vtkIdTypeArray(T,deep=True))
|
||||||
|
|
||||||
vtk_data = vtk.vtkUnstructuredGrid()
|
vtk_data = vtkUnstructuredGrid()
|
||||||
vtk_data.SetPoints(vtk_nodes)
|
vtk_data.SetPoints(vtk_nodes)
|
||||||
cell_types = {'TRIANGLE':vtk.VTK_TRIANGLE, 'QUAD':vtk.VTK_QUAD,
|
cell_types = {'TRIANGLE':VTK_TRIANGLE, 'QUAD':VTK_QUAD,
|
||||||
'TETRA' :vtk.VTK_TETRA, 'HEXAHEDRON':vtk.VTK_HEXAHEDRON}
|
'TETRA' :VTK_TETRA, 'HEXAHEDRON':VTK_HEXAHEDRON}
|
||||||
vtk_data.SetCells(cell_types[cell_type.split("_",1)[-1].upper()],cells)
|
vtk_data.SetCells(cell_types[cell_type.split("_",1)[-1].upper()],cells)
|
||||||
|
|
||||||
return VTK(vtk_data)
|
return VTK(vtk_data)
|
||||||
|
@ -226,7 +270,7 @@ class VTK:
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def from_poly_data(points: np.ndarray) -> 'VTK':
|
def from_poly_data(points: np.ndarray) -> 'VTK':
|
||||||
"""
|
"""
|
||||||
Create VTK of type vtk.polyData.
|
Create VTK of type polyData.
|
||||||
|
|
||||||
This is the common type for point-wise data.
|
This is the common type for point-wise data.
|
||||||
|
|
||||||
|
@ -242,15 +286,15 @@ class VTK:
|
||||||
|
|
||||||
"""
|
"""
|
||||||
N = points.shape[0]
|
N = points.shape[0]
|
||||||
vtk_points = vtk.vtkPoints()
|
vtk_points = vtkPoints()
|
||||||
vtk_points.SetData(np_to_vtk(np.ascontiguousarray(points)))
|
vtk_points.SetData(numpy_to_vtk(np.ascontiguousarray(points)))
|
||||||
|
|
||||||
vtk_cells = vtk.vtkCellArray()
|
vtk_cells = vtkCellArray()
|
||||||
vtk_cells.SetNumberOfCells(N)
|
vtk_cells.SetNumberOfCells(N)
|
||||||
vtk_cells.SetCells(N,np_to_vtkIdTypeArray(np.stack((np.ones (N,dtype=np.int64),
|
vtk_cells.SetCells(N,numpy_to_vtkIdTypeArray(np.stack((np.ones (N,dtype=np.int64),
|
||||||
np.arange(N,dtype=np.int64)),axis=1).ravel(),deep=True))
|
np.arange(N,dtype=np.int64)),axis=1).ravel(),deep=True))
|
||||||
|
|
||||||
vtk_data = vtk.vtkPolyData()
|
vtk_data = vtkPolyData()
|
||||||
vtk_data.SetPoints(vtk_points)
|
vtk_data.SetPoints(vtk_points)
|
||||||
vtk_data.SetVerts(vtk_cells)
|
vtk_data.SetVerts(vtk_cells)
|
||||||
|
|
||||||
|
@ -260,7 +304,7 @@ class VTK:
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def from_rectilinear_grid(grid: FloatSequence) -> 'VTK':
|
def from_rectilinear_grid(grid: FloatSequence) -> 'VTK':
|
||||||
"""
|
"""
|
||||||
Create VTK of type vtk.vtkRectilinearGrid.
|
Create VTK of type vtkRectilinearGrid.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
|
@ -273,9 +317,9 @@ class VTK:
|
||||||
VTK-based geometry without nodal or cell data.
|
VTK-based geometry without nodal or cell data.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
vtk_data = vtk.vtkRectilinearGrid()
|
vtk_data = vtkRectilinearGrid()
|
||||||
vtk_data.SetDimensions(*map(len,grid))
|
vtk_data.SetDimensions(*map(len,grid))
|
||||||
coord = [np_to_vtk(np.array(grid[i]),deep=True) for i in [0,1,2]]
|
coord = [numpy_to_vtk(np.array(grid[i]),deep=True) for i in [0,1,2]]
|
||||||
[coord[i].SetName(n) for i,n in enumerate(['x','y','z'])]
|
[coord[i].SetName(n) for i,n in enumerate(['x','y','z'])]
|
||||||
vtk_data.SetXCoordinates(coord[0])
|
vtk_data.SetXCoordinates(coord[0])
|
||||||
vtk_data.SetYCoordinates(coord[1])
|
vtk_data.SetYCoordinates(coord[1])
|
||||||
|
@ -293,10 +337,10 @@ class VTK:
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
fname : str or pathlib.Path
|
fname : str or pathlib.Path
|
||||||
Filename for reading.
|
Filename to read.
|
||||||
Valid extensions are .vti, .vtu, .vtp, .vtr, and .vtk.
|
Valid extensions are .vti, .vtu, .vtp, .vtr, and .vtk.
|
||||||
dataset_type : {'ImageData', 'UnstructuredGrid', 'PolyData', 'RectilinearGrid'}, optional
|
dataset_type : {'ImageData', 'UnstructuredGrid', 'PolyData', 'RectilinearGrid'}, optional
|
||||||
Name of the vtk.vtkDataSet subclass when opening a .vtk file.
|
Name of the vtkDataSet subclass when opening a .vtk file.
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
-------
|
-------
|
||||||
|
@ -307,7 +351,7 @@ class VTK:
|
||||||
if not Path(fname).expanduser().is_file(): # vtk has a strange error handling
|
if not Path(fname).expanduser().is_file(): # vtk has a strange error handling
|
||||||
raise FileNotFoundError(f'file "{fname}" not found')
|
raise FileNotFoundError(f'file "{fname}" not found')
|
||||||
if (ext := Path(fname).suffix) == '.vtk' or dataset_type is not None:
|
if (ext := Path(fname).suffix) == '.vtk' or dataset_type is not None:
|
||||||
reader = vtk.vtkGenericDataObjectReader()
|
reader = vtkGenericDataObjectReader()
|
||||||
reader.SetFileName(str(Path(fname).expanduser()))
|
reader.SetFileName(str(Path(fname).expanduser()))
|
||||||
if dataset_type is None:
|
if dataset_type is None:
|
||||||
raise TypeError('dataset type for *.vtk file not given')
|
raise TypeError('dataset type for *.vtk file not given')
|
||||||
|
@ -327,13 +371,13 @@ class VTK:
|
||||||
raise TypeError(f'unknown dataset type "{dataset_type}" for vtk file')
|
raise TypeError(f'unknown dataset type "{dataset_type}" for vtk file')
|
||||||
else:
|
else:
|
||||||
if ext == '.vti':
|
if ext == '.vti':
|
||||||
reader = vtk.vtkXMLImageDataReader()
|
reader = vtkXMLImageDataReader()
|
||||||
elif ext == '.vtu':
|
elif ext == '.vtu':
|
||||||
reader = vtk.vtkXMLUnstructuredGridReader()
|
reader = vtkXMLUnstructuredGridReader()
|
||||||
elif ext == '.vtp':
|
elif ext == '.vtp':
|
||||||
reader = vtk.vtkXMLPolyDataReader()
|
reader = vtkXMLPolyDataReader()
|
||||||
elif ext == '.vtr':
|
elif ext == '.vtr':
|
||||||
reader = vtk.vtkXMLRectilinearGridReader()
|
reader = vtkXMLRectilinearGridReader()
|
||||||
else:
|
else:
|
||||||
raise TypeError(f'unknown file extension "{ext}"')
|
raise TypeError(f'unknown file extension "{ext}"')
|
||||||
|
|
||||||
|
@ -352,7 +396,7 @@ class VTK:
|
||||||
|
|
||||||
def as_ASCII(self) -> str:
|
def as_ASCII(self) -> str:
|
||||||
"""ASCII representation of the VTK data."""
|
"""ASCII representation of the VTK data."""
|
||||||
writer = vtk.vtkDataSetWriter()
|
writer = vtkDataSetWriter()
|
||||||
writer.SetHeader(f'# {util.execution_stamp("VTK")}')
|
writer.SetHeader(f'# {util.execution_stamp("VTK")}')
|
||||||
writer.WriteToOutputStringOn()
|
writer.WriteToOutputStringOn()
|
||||||
writer.SetInputData(self.vtk_data)
|
writer.SetInputData(self.vtk_data)
|
||||||
|
@ -370,21 +414,21 @@ class VTK:
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
fname : str or pathlib.Path
|
fname : str or pathlib.Path
|
||||||
Filename for writing.
|
Filename to write.
|
||||||
parallel : bool, optional
|
parallel : bool, optional
|
||||||
Write data in parallel background process. Defaults to True.
|
Write data in parallel background process. Defaults to True.
|
||||||
compress : bool, optional
|
compress : bool, optional
|
||||||
Compress with zlib algorithm. Defaults to True.
|
Compress with zlib algorithm. Defaults to True.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if isinstance(self.vtk_data,vtk.vtkImageData):
|
if isinstance(self.vtk_data,vtkImageData):
|
||||||
writer = vtk.vtkXMLImageDataWriter()
|
writer = vtkXMLImageDataWriter()
|
||||||
elif isinstance(self.vtk_data,vtk.vtkUnstructuredGrid):
|
elif isinstance(self.vtk_data,vtkUnstructuredGrid):
|
||||||
writer = vtk.vtkXMLUnstructuredGridWriter()
|
writer = vtkXMLUnstructuredGridWriter()
|
||||||
elif isinstance(self.vtk_data,vtk.vtkPolyData):
|
elif isinstance(self.vtk_data,vtkPolyData):
|
||||||
writer = vtk.vtkXMLPolyDataWriter()
|
writer = vtkXMLPolyDataWriter()
|
||||||
elif isinstance(self.vtk_data,vtk.vtkRectilinearGrid):
|
elif isinstance(self.vtk_data,vtkRectilinearGrid):
|
||||||
writer = vtk.vtkXMLRectilinearGridWriter()
|
writer = vtkXMLRectilinearGridWriter()
|
||||||
|
|
||||||
default_ext = '.'+writer.GetDefaultFileExtension()
|
default_ext = '.'+writer.GetDefaultFileExtension()
|
||||||
ext = Path(fname).suffix
|
ext = Path(fname).suffix
|
||||||
|
@ -433,6 +477,11 @@ class VTK:
|
||||||
Data to add or replace. Each table label is individually considered.
|
Data to add or replace. Each table label is individually considered.
|
||||||
Number of rows needs to match either number of cells or number of points.
|
Number of rows needs to match either number of cells or number of points.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
updated : damask.VTK
|
||||||
|
Updated VTK-based geometry.
|
||||||
|
|
||||||
Notes
|
Notes
|
||||||
-----
|
-----
|
||||||
If the number of cells equals the number of points, the data is added to both.
|
If the number of cells equals the number of points, the data is added to both.
|
||||||
|
@ -451,11 +500,11 @@ class VTK:
|
||||||
.astype(np.single if data.dtype in [np.double,np.longdouble] else data.dtype)
|
.astype(np.single if data.dtype in [np.double,np.longdouble] else data.dtype)
|
||||||
|
|
||||||
if data.dtype.type is np.str_:
|
if data.dtype.type is np.str_:
|
||||||
d = vtk.vtkStringArray()
|
d = vtkStringArray()
|
||||||
for s in np.squeeze(data_):
|
for s in np.squeeze(data_):
|
||||||
d.InsertNextValue(s)
|
d.InsertNextValue(s)
|
||||||
else:
|
else:
|
||||||
d = np_to_vtk(data_,deep=True)
|
d = numpy_to_vtk(data_,deep=True)
|
||||||
|
|
||||||
d.SetName(label)
|
d.SetName(label)
|
||||||
|
|
||||||
|
@ -513,7 +562,7 @@ class VTK:
|
||||||
for a in range(cell_data.GetNumberOfArrays()):
|
for a in range(cell_data.GetNumberOfArrays()):
|
||||||
if cell_data.GetArrayName(a) == label:
|
if cell_data.GetArrayName(a) == label:
|
||||||
try:
|
try:
|
||||||
return vtk_to_np(cell_data.GetArray(a))
|
return vtk_to_numpy(cell_data.GetArray(a))
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
vtk_array = cell_data.GetAbstractArray(a) # string array
|
vtk_array = cell_data.GetAbstractArray(a) # string array
|
||||||
|
|
||||||
|
@ -521,7 +570,7 @@ class VTK:
|
||||||
for a in range(point_data.GetNumberOfArrays()):
|
for a in range(point_data.GetNumberOfArrays()):
|
||||||
if point_data.GetArrayName(a) == label:
|
if point_data.GetArrayName(a) == label:
|
||||||
try:
|
try:
|
||||||
return vtk_to_np(point_data.GetArray(a))
|
return vtk_to_numpy(point_data.GetArray(a))
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
vtk_array = point_data.GetAbstractArray(a) # string array
|
vtk_array = point_data.GetAbstractArray(a) # string array
|
||||||
|
|
||||||
|
@ -548,7 +597,7 @@ class VTK:
|
||||||
Notes
|
Notes
|
||||||
-----
|
-----
|
||||||
The first component is shown when visualizing vector datasets
|
The first component is shown when visualizing vector datasets
|
||||||
(this includes tensor datasets because they are flattened).
|
(this includes tensor datasets as they are flattened).
|
||||||
|
|
||||||
"""
|
"""
|
||||||
# See http://compilatrix.com/article/vtk-1 for possible improvements.
|
# See http://compilatrix.com/article/vtk-1 for possible improvements.
|
||||||
|
@ -567,7 +616,7 @@ class VTK:
|
||||||
width = 1024
|
width = 1024
|
||||||
height = 768
|
height = 768
|
||||||
|
|
||||||
lut = vtk.vtkLookupTable()
|
lut = vtkLookupTable()
|
||||||
colormap_ = Colormap.from_predefined(colormap) if isinstance(colormap,str) else \
|
colormap_ = Colormap.from_predefined(colormap) if isinstance(colormap,str) else \
|
||||||
colormap
|
colormap
|
||||||
lut.SetNumberOfTableValues(len(colormap_.colors))
|
lut.SetNumberOfTableValues(len(colormap_.colors))
|
||||||
|
@ -576,33 +625,33 @@ class VTK:
|
||||||
lut.Build()
|
lut.Build()
|
||||||
|
|
||||||
self.vtk_data.GetCellData().SetActiveScalars(label)
|
self.vtk_data.GetCellData().SetActiveScalars(label)
|
||||||
mapper = vtk.vtkDataSetMapper()
|
mapper = vtkDataSetMapper()
|
||||||
mapper.SetInputData(self.vtk_data)
|
mapper.SetInputData(self.vtk_data)
|
||||||
mapper.SetLookupTable(lut)
|
mapper.SetLookupTable(lut)
|
||||||
mapper.SetScalarRange(self.vtk_data.GetScalarRange())
|
mapper.SetScalarRange(self.vtk_data.GetScalarRange())
|
||||||
|
|
||||||
actor = vtk.vtkActor()
|
actor = vtkActor()
|
||||||
actor.SetMapper(mapper)
|
actor.SetMapper(mapper)
|
||||||
actor.GetProperty().SetColor(230/255,150/255,68/255)
|
actor.GetProperty().SetColor(230/255,150/255,68/255)
|
||||||
|
|
||||||
ren = vtk.vtkRenderer()
|
ren = vtkRenderer()
|
||||||
ren.AddActor(actor)
|
ren.AddActor(actor)
|
||||||
if label is None:
|
if label is None:
|
||||||
ren.SetBackground(67/255,128/255,208/255)
|
ren.SetBackground(67/255,128/255,208/255)
|
||||||
else:
|
else:
|
||||||
colormap_vtk = vtk.vtkScalarBarActor()
|
colormap_vtk = vtkScalarBarActor()
|
||||||
colormap_vtk.SetLookupTable(lut)
|
colormap_vtk.SetLookupTable(lut)
|
||||||
colormap_vtk.SetTitle(label)
|
colormap_vtk.SetTitle(label)
|
||||||
colormap_vtk.SetMaximumWidthInPixels(width//100)
|
colormap_vtk.SetMaximumWidthInPixels(width//100)
|
||||||
ren.AddActor2D(colormap_vtk)
|
ren.AddActor2D(colormap_vtk)
|
||||||
ren.SetBackground(0.3,0.3,0.3)
|
ren.SetBackground(0.3,0.3,0.3)
|
||||||
|
|
||||||
window = vtk.vtkRenderWindow()
|
window = vtkRenderWindow()
|
||||||
window.AddRenderer(ren)
|
window.AddRenderer(ren)
|
||||||
window.SetSize(width,height)
|
window.SetSize(width,height)
|
||||||
window.SetWindowName(util.execution_stamp('VTK','show'))
|
window.SetWindowName(util.execution_stamp('VTK','show'))
|
||||||
|
|
||||||
iren = vtk.vtkRenderWindowInteractor()
|
iren = vtkRenderWindowInteractor()
|
||||||
iren.SetRenderWindow(window)
|
iren.SetRenderWindow(window)
|
||||||
if os.name == 'posix' and 'DISPLAY' not in os.environ:
|
if os.name == 'posix' and 'DISPLAY' not in os.environ:
|
||||||
print('Found no rendering device')
|
print('Found no rendering device')
|
||||||
|
|
|
@ -402,7 +402,7 @@ def displacement_node(size: _FloatSequence,
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
-------
|
-------
|
||||||
u_p : numpy.ndarray, shape (:,:,:,3)
|
u_n : numpy.ndarray, shape (:,:,:,3)
|
||||||
Nodal displacements.
|
Nodal displacements.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
@ -564,17 +564,10 @@ def unravel_index(idx: _np.ndarray) -> _np.ndarray:
|
||||||
>>> seq = np.arange(6).reshape((3,2,1),order='F')
|
>>> seq = np.arange(6).reshape((3,2,1),order='F')
|
||||||
>>> (coord_idx := damask.grid_filters.unravel_index(seq))
|
>>> (coord_idx := damask.grid_filters.unravel_index(seq))
|
||||||
array([[[[0, 0, 0]],
|
array([[[[0, 0, 0]],
|
||||||
|
|
||||||
[[0, 1, 0]]],
|
[[0, 1, 0]]],
|
||||||
|
|
||||||
|
|
||||||
[[[1, 0, 0]],
|
[[[1, 0, 0]],
|
||||||
|
|
||||||
[[1, 1, 0]]],
|
[[1, 1, 0]]],
|
||||||
|
|
||||||
|
|
||||||
[[[2, 0, 0]],
|
[[[2, 0, 0]],
|
||||||
|
|
||||||
[[2, 1, 0]]]])
|
[[2, 1, 0]]]])
|
||||||
>>> coord_idx[1,1,0]
|
>>> coord_idx[1,1,0]
|
||||||
array([1, 1, 0])
|
array([1, 1, 0])
|
||||||
|
@ -608,17 +601,12 @@ def ravel_index(idx: _np.ndarray) -> _np.ndarray:
|
||||||
>>> import damask
|
>>> import damask
|
||||||
>>> (rev := np.array([[1,1,0],[0,1,0],[1,0,0],[0,0,0]]).reshape((2,2,1,3)))
|
>>> (rev := np.array([[1,1,0],[0,1,0],[1,0,0],[0,0,0]]).reshape((2,2,1,3)))
|
||||||
array([[[[1, 1, 0]],
|
array([[[[1, 1, 0]],
|
||||||
|
|
||||||
[[0, 1, 0]]],
|
[[0, 1, 0]]],
|
||||||
|
|
||||||
|
|
||||||
[[[1, 0, 0]],
|
[[[1, 0, 0]],
|
||||||
|
|
||||||
[[0, 0, 0]]]])
|
[[0, 0, 0]]]])
|
||||||
>>> (flat_idx := damask.grid_filters.ravel_index(rev))
|
>>> (flat_idx := damask.grid_filters.ravel_index(rev))
|
||||||
array([[[3],
|
array([[[3],
|
||||||
[2]],
|
[2]],
|
||||||
|
|
||||||
[[1],
|
[[1],
|
||||||
[0]]])
|
[0]]])
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ All routines operate on numpy.ndarrays of shape (...,3,3).
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from typing import Sequence as _Sequence
|
from typing import Sequence as _Sequence#, Literal as _Literal
|
||||||
|
|
||||||
import numpy as _np
|
import numpy as _np
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ from . import _rotation
|
||||||
|
|
||||||
|
|
||||||
def deformation_Cauchy_Green_left(F: _np.ndarray) -> _np.ndarray:
|
def deformation_Cauchy_Green_left(F: _np.ndarray) -> _np.ndarray:
|
||||||
"""
|
r"""
|
||||||
Calculate left Cauchy-Green deformation tensor (Finger deformation tensor).
|
Calculate left Cauchy-Green deformation tensor (Finger deformation tensor).
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
|
@ -27,12 +27,18 @@ def deformation_Cauchy_Green_left(F: _np.ndarray) -> _np.ndarray:
|
||||||
B : numpy.ndarray, shape (...,3,3)
|
B : numpy.ndarray, shape (...,3,3)
|
||||||
Left Cauchy-Green deformation tensor.
|
Left Cauchy-Green deformation tensor.
|
||||||
|
|
||||||
|
Notes
|
||||||
|
-----
|
||||||
|
.. math::
|
||||||
|
|
||||||
|
\vb{B} = \vb{F} \vb{F}^\text{T}
|
||||||
|
|
||||||
"""
|
"""
|
||||||
return _np.matmul(F,_tensor.transpose(F))
|
return _np.matmul(F,_tensor.transpose(F))
|
||||||
|
|
||||||
|
|
||||||
def deformation_Cauchy_Green_right(F: _np.ndarray) -> _np.ndarray:
|
def deformation_Cauchy_Green_right(F: _np.ndarray) -> _np.ndarray:
|
||||||
"""
|
r"""
|
||||||
Calculate right Cauchy-Green deformation tensor.
|
Calculate right Cauchy-Green deformation tensor.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
|
@ -45,12 +51,18 @@ def deformation_Cauchy_Green_right(F: _np.ndarray) -> _np.ndarray:
|
||||||
C : numpy.ndarray, shape (...,3,3)
|
C : numpy.ndarray, shape (...,3,3)
|
||||||
Right Cauchy-Green deformation tensor.
|
Right Cauchy-Green deformation tensor.
|
||||||
|
|
||||||
|
Notes
|
||||||
|
-----
|
||||||
|
.. math::
|
||||||
|
|
||||||
|
\vb{C} = \vb{F}^\text{T} \vb{F}
|
||||||
|
|
||||||
"""
|
"""
|
||||||
return _np.matmul(_tensor.transpose(F),F)
|
return _np.matmul(_tensor.transpose(F),F)
|
||||||
|
|
||||||
|
|
||||||
def equivalent_strain_Mises(epsilon: _np.ndarray) -> _np.ndarray:
|
def equivalent_strain_Mises(epsilon: _np.ndarray) -> _np.ndarray:
|
||||||
"""
|
r"""
|
||||||
Calculate the Mises equivalent of a strain tensor.
|
Calculate the Mises equivalent of a strain tensor.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
|
@ -63,12 +75,23 @@ def equivalent_strain_Mises(epsilon: _np.ndarray) -> _np.ndarray:
|
||||||
epsilon_vM : numpy.ndarray, shape (...)
|
epsilon_vM : numpy.ndarray, shape (...)
|
||||||
Von Mises equivalent strain of epsilon.
|
Von Mises equivalent strain of epsilon.
|
||||||
|
|
||||||
|
Notes
|
||||||
|
-----
|
||||||
|
The von Mises equivalent of a strain tensor is defined as:
|
||||||
|
|
||||||
|
.. math::
|
||||||
|
|
||||||
|
\epsilon_\text{vM} = \sqrt{\frac{2}{3}\,\epsilon^\prime_{ij} \epsilon^\prime_{ij}}
|
||||||
|
|
||||||
|
where :math:`\vb*{\epsilon}^\prime` is the deviatoric part
|
||||||
|
of the strain tensor.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
return _equivalent_Mises(epsilon,2.0/3.0)
|
return _equivalent_Mises(epsilon,2.0/3.0)
|
||||||
|
|
||||||
|
|
||||||
def equivalent_stress_Mises(sigma: _np.ndarray) -> _np.ndarray:
|
def equivalent_stress_Mises(sigma: _np.ndarray) -> _np.ndarray:
|
||||||
"""
|
r"""
|
||||||
Calculate the Mises equivalent of a stress tensor.
|
Calculate the Mises equivalent of a stress tensor.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
|
@ -81,6 +104,17 @@ def equivalent_stress_Mises(sigma: _np.ndarray) -> _np.ndarray:
|
||||||
sigma_vM : numpy.ndarray, shape (...)
|
sigma_vM : numpy.ndarray, shape (...)
|
||||||
Von Mises equivalent stress of sigma.
|
Von Mises equivalent stress of sigma.
|
||||||
|
|
||||||
|
Notes
|
||||||
|
-----
|
||||||
|
The von Mises equivalent of a stress tensor is defined as:
|
||||||
|
|
||||||
|
.. math::
|
||||||
|
|
||||||
|
\sigma_\text{vM} = \sqrt{\frac{3}{2}\,\sigma^\prime_{ij} \sigma^\prime_{ij}}
|
||||||
|
|
||||||
|
where :math:`\vb*{\sigma}^\prime` is the deviatoric part
|
||||||
|
of the stress tensor.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
return _equivalent_Mises(sigma,3.0/2.0)
|
return _equivalent_Mises(sigma,3.0/2.0)
|
||||||
|
|
||||||
|
@ -105,7 +139,7 @@ def maximum_shear(T_sym: _np.ndarray) -> _np.ndarray:
|
||||||
|
|
||||||
|
|
||||||
def rotation(T: _np.ndarray) -> _rotation.Rotation:
|
def rotation(T: _np.ndarray) -> _rotation.Rotation:
|
||||||
"""
|
r"""
|
||||||
Calculate the rotational part of a tensor.
|
Calculate the rotational part of a tensor.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
|
@ -118,23 +152,35 @@ def rotation(T: _np.ndarray) -> _rotation.Rotation:
|
||||||
R : damask.Rotation, shape (...)
|
R : damask.Rotation, shape (...)
|
||||||
Rotational part of the vector.
|
Rotational part of the vector.
|
||||||
|
|
||||||
|
Notes
|
||||||
|
-----
|
||||||
|
The rotational part is calculated from the polar decomposition:
|
||||||
|
|
||||||
|
.. math::
|
||||||
|
|
||||||
|
\vb{R} = \vb{T} \vb{U}^{-1} = \vb{V}^{-1} \vb{T}
|
||||||
|
|
||||||
|
where :math:`\vb{V}` and :math:`\vb{U}` are the left
|
||||||
|
and right stretch tensor, respectively.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
return _rotation.Rotation.from_matrix(_polar_decomposition(T,'R')[0])
|
return _rotation.Rotation.from_matrix(_polar_decomposition(T,'R')[0])
|
||||||
|
|
||||||
|
|
||||||
def strain(F: _np.ndarray,
|
def strain(F: _np.ndarray,
|
||||||
|
#t: _Literal['V', 'U'], should work, but rejected by SC
|
||||||
t: str,
|
t: str,
|
||||||
m: float) -> _np.ndarray:
|
m: float) -> _np.ndarray:
|
||||||
"""
|
r"""
|
||||||
Calculate strain tensor (Seth–Hill family).
|
Calculate strain tensor (Seth–Hill family).
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
F : numpy.ndarray, shape (...,3,3)
|
F : numpy.ndarray, shape (...,3,3)
|
||||||
Deformation gradient.
|
Deformation gradient.
|
||||||
t : {‘V’, ‘U’}
|
t : {'V', 'U'}
|
||||||
Type of the polar decomposition, ‘V’ for left stretch tensor
|
Type of the polar decomposition, 'V' for left stretch tensor
|
||||||
and ‘U’ for right stretch tensor.
|
or 'U' for right stretch tensor.
|
||||||
m : float
|
m : float
|
||||||
Order of the strain.
|
Order of the strain.
|
||||||
|
|
||||||
|
@ -143,25 +189,25 @@ def strain(F: _np.ndarray,
|
||||||
epsilon : numpy.ndarray, shape (...,3,3)
|
epsilon : numpy.ndarray, shape (...,3,3)
|
||||||
Strain of F.
|
Strain of F.
|
||||||
|
|
||||||
|
Notes
|
||||||
|
-----
|
||||||
|
The strain is defined as:
|
||||||
|
|
||||||
|
.. math::
|
||||||
|
|
||||||
|
\vb*{\epsilon}_V^{(m)} = \frac{1}{2m} (\vb{V}^{2m} - \vb{I}) \\\\
|
||||||
|
\vb*{\epsilon}_U^{(m)} = \frac{1}{2m} (\vb{U}^{2m} - \vb{I})
|
||||||
|
|
||||||
References
|
References
|
||||||
----------
|
----------
|
||||||
https://en.wikipedia.org/wiki/Finite_strain_theory
|
| https://en.wikipedia.org/wiki/Finite_strain_theory
|
||||||
https://de.wikipedia.org/wiki/Verzerrungstensor
|
| https://de.wikipedia.org/wiki/Verzerrungstensor
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if t == 'V':
|
if t not in ['V', 'U']: raise ValueError('polar decomposition type not in {V, U}')
|
||||||
w,n = _np.linalg.eigh(deformation_Cauchy_Green_left(F))
|
w,n = _np.linalg.eigh(deformation_Cauchy_Green_left(F) if t=='V' else deformation_Cauchy_Green_right(F))
|
||||||
elif t == 'U':
|
return 0.5 * _np.einsum('...j,...kj,...lj',_np.log(w),n,n) if m == 0.0 \
|
||||||
w,n = _np.linalg.eigh(deformation_Cauchy_Green_right(F))
|
else 0.5/m * (_np.einsum('...j,...kj,...lj', w**m,n,n) - _np.eye(3))
|
||||||
|
|
||||||
if m > 0.0:
|
|
||||||
eps = 1.0/(2.0*abs(m)) * (+ _np.einsum('...j,...kj,...lj',w**m,n,n) - _np.eye(3))
|
|
||||||
elif m < 0.0:
|
|
||||||
eps = 1.0/(2.0*abs(m)) * (- _np.einsum('...j,...kj,...lj',w**m,n,n) + _np.eye(3))
|
|
||||||
else:
|
|
||||||
eps = _np.einsum('...j,...kj,...lj',0.5*_np.log(w),n,n)
|
|
||||||
|
|
||||||
return eps
|
|
||||||
|
|
||||||
|
|
||||||
def stress_Cauchy(P: _np.ndarray,
|
def stress_Cauchy(P: _np.ndarray,
|
||||||
|
@ -212,7 +258,7 @@ def stress_second_Piola_Kirchhoff(P: _np.ndarray,
|
||||||
|
|
||||||
|
|
||||||
def stretch_left(T: _np.ndarray) -> _np.ndarray:
|
def stretch_left(T: _np.ndarray) -> _np.ndarray:
|
||||||
"""
|
r"""
|
||||||
Calculate left stretch of a tensor.
|
Calculate left stretch of a tensor.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
|
@ -225,12 +271,23 @@ def stretch_left(T: _np.ndarray) -> _np.ndarray:
|
||||||
V : numpy.ndarray, shape (...,3,3)
|
V : numpy.ndarray, shape (...,3,3)
|
||||||
Left stretch tensor from Polar decomposition of T.
|
Left stretch tensor from Polar decomposition of T.
|
||||||
|
|
||||||
|
Notes
|
||||||
|
-----
|
||||||
|
The left stretch tensor is calculated from the
|
||||||
|
polar decomposition:
|
||||||
|
|
||||||
|
.. math::
|
||||||
|
|
||||||
|
\vb{V} = \vb{T} \vb{R}^\text{T}
|
||||||
|
|
||||||
|
where :math:`\vb{R}` is a rotation.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
return _polar_decomposition(T,'V')[0]
|
return _polar_decomposition(T,'V')[0]
|
||||||
|
|
||||||
|
|
||||||
def stretch_right(T: _np.ndarray) -> _np.ndarray:
|
def stretch_right(T: _np.ndarray) -> _np.ndarray:
|
||||||
"""
|
r"""
|
||||||
Calculate right stretch of a tensor.
|
Calculate right stretch of a tensor.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
|
@ -243,6 +300,17 @@ def stretch_right(T: _np.ndarray) -> _np.ndarray:
|
||||||
U : numpy.ndarray, shape (...,3,3)
|
U : numpy.ndarray, shape (...,3,3)
|
||||||
Left stretch tensor from Polar decomposition of T.
|
Left stretch tensor from Polar decomposition of T.
|
||||||
|
|
||||||
|
Notes
|
||||||
|
-----
|
||||||
|
The right stretch tensor is calculated from the
|
||||||
|
polar decomposition:
|
||||||
|
|
||||||
|
.. math::
|
||||||
|
|
||||||
|
\vb{U} = \vb{R}^\text{T} \vb{T}
|
||||||
|
|
||||||
|
where :math:`\vb{R}` is a rotation.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
return _polar_decomposition(T,'U')[0]
|
return _polar_decomposition(T,'U')[0]
|
||||||
|
|
||||||
|
@ -257,8 +325,13 @@ def _polar_decomposition(T: _np.ndarray,
|
||||||
T : numpy.ndarray, shape (...,3,3)
|
T : numpy.ndarray, shape (...,3,3)
|
||||||
Tensor of which the singular values are computed.
|
Tensor of which the singular values are computed.
|
||||||
requested : sequence of {'R', 'U', 'V'}
|
requested : sequence of {'R', 'U', 'V'}
|
||||||
Requested outputs: ‘R’ for the rotation tensor,
|
Requested outputs: 'R' for the rotation tensor,
|
||||||
‘V’ for left stretch tensor, and ‘U’ for right stretch tensor.
|
'V' for left stretch tensor, and 'U' for right stretch tensor.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
VRU : tuple of numpy.ndarray, shape (...,3,3)
|
||||||
|
Requested components of the singular value decomposition.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
u, _, vh = _np.linalg.svd(T)
|
u, _, vh = _np.linalg.svd(T)
|
||||||
|
@ -290,6 +363,11 @@ def _equivalent_Mises(T_sym: _np.ndarray,
|
||||||
s : float
|
s : float
|
||||||
Scaling factor (2/3 for strain, 3/2 for stress).
|
Scaling factor (2/3 for strain, 3/2 for stress).
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
eq : numpy.ndarray, shape (...)
|
||||||
|
Scaled second invariant of the deviatoric part of T_sym.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
d = _tensor.deviatoric(T_sym)
|
d = _tensor.deviatoric(T_sym)
|
||||||
return _np.sqrt(s*_np.sum(d**2.0,axis=(-1,-2)))
|
return _np.sqrt(s*_np.sum(d**2.0,axis=(-1,-2)))
|
||||||
|
|
|
@ -21,7 +21,7 @@ def from_random(size: _FloatSequence,
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
size : sequence of float, len (3)
|
size : sequence of float, len (3)
|
||||||
Physical size of the seeding domain.
|
Edge lengths of the seeding domain.
|
||||||
N_seeds : int
|
N_seeds : int
|
||||||
Number of seeds.
|
Number of seeds.
|
||||||
cells : sequence of int, len (3), optional.
|
cells : sequence of int, len (3), optional.
|
||||||
|
@ -56,12 +56,12 @@ def from_Poisson_disc(size: _FloatSequence,
|
||||||
periodic: bool = True,
|
periodic: bool = True,
|
||||||
rng_seed: _Optional[_NumpyRngSeed] = None) -> _np.ndarray:
|
rng_seed: _Optional[_NumpyRngSeed] = None) -> _np.ndarray:
|
||||||
"""
|
"""
|
||||||
Place seeds according to a Poisson disc distribution.
|
Place seeds following a Poisson disc distribution.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
size : sequence of float, len (3)
|
size : sequence of float, len (3)
|
||||||
Physical size of the seeding domain.
|
Edge lengths of the seeding domain.
|
||||||
N_seeds : int
|
N_seeds : int
|
||||||
Number of seeds.
|
Number of seeds.
|
||||||
N_candidates : int
|
N_candidates : int
|
||||||
|
@ -70,6 +70,7 @@ def from_Poisson_disc(size: _FloatSequence,
|
||||||
Minimum acceptable distance to other seeds.
|
Minimum acceptable distance to other seeds.
|
||||||
periodic : bool, optional
|
periodic : bool, optional
|
||||||
Calculate minimum distance for periodically repeated grid.
|
Calculate minimum distance for periodically repeated grid.
|
||||||
|
Defaults to True.
|
||||||
rng_seed : {None, int, array_like[ints], SeedSequence, BitGenerator, Generator}, optional
|
rng_seed : {None, int, array_like[ints], SeedSequence, BitGenerator, Generator}, optional
|
||||||
A seed to initialize the BitGenerator. Defaults to None.
|
A seed to initialize the BitGenerator. Defaults to None.
|
||||||
If None, then fresh, unpredictable entropy will be pulled from the OS.
|
If None, then fresh, unpredictable entropy will be pulled from the OS.
|
||||||
|
@ -123,14 +124,36 @@ def from_grid(grid,
|
||||||
Consider all material IDs except those in selection. Defaults to False.
|
Consider all material IDs except those in selection. Defaults to False.
|
||||||
average : bool, optional
|
average : bool, optional
|
||||||
Seed corresponds to center of gravity of material ID cloud.
|
Seed corresponds to center of gravity of material ID cloud.
|
||||||
|
Defaults to False.
|
||||||
periodic : bool, optional
|
periodic : bool, optional
|
||||||
Center of gravity accounts for periodic boundaries.
|
Center of gravity accounts for periodic boundaries.
|
||||||
|
Defaults to True.
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
-------
|
-------
|
||||||
coords, materials : numpy.ndarray, shape (:,3); numpy.ndarray, shape (:)
|
coords, materials : numpy.ndarray, shape (:,3); numpy.ndarray, shape (:)
|
||||||
Seed coordinates in 3D space, material IDs.
|
Seed coordinates in 3D space, material IDs.
|
||||||
|
|
||||||
|
Examples
|
||||||
|
--------
|
||||||
|
Recreate seeds from Voronoi tessellation.
|
||||||
|
|
||||||
|
>>> import numpy as np
|
||||||
|
>>> import scipy.spatial
|
||||||
|
>>> import damask
|
||||||
|
>>> seeds = damask.seeds.from_random(np.ones(3),29,[128]*3)
|
||||||
|
>>> (g := damask.Grid.from_Voronoi_tessellation([128]*3,np.ones(3),seeds))
|
||||||
|
cells: 128 × 128 × 128
|
||||||
|
size: 1.0 × 1.0 × 1.0 m³
|
||||||
|
origin: 0.0 0.0 0.0 m
|
||||||
|
# materials: 29
|
||||||
|
>>> COG,matID = damask.seeds.from_grid(g,average=True)
|
||||||
|
>>> distance,ID = scipy.spatial.KDTree(COG,boxsize=g.size).query(seeds)
|
||||||
|
>>> np.max(distance) / np.linalg.norm(g.size/g.cells)
|
||||||
|
7.8057356746350415
|
||||||
|
>>> (ID == matID).all()
|
||||||
|
True
|
||||||
|
|
||||||
"""
|
"""
|
||||||
material = grid.material.reshape((-1,1),order='F')
|
material = grid.material.reshape((-1,1),order='F')
|
||||||
mask = _np.full(grid.cells.prod(),True,dtype=bool) if selection is None else \
|
mask = _np.full(grid.cells.prod(),True,dtype=bool) if selection is None else \
|
||||||
|
|
|
@ -2,6 +2,7 @@ import subprocess
|
||||||
import shlex
|
import shlex
|
||||||
import re
|
import re
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from typing import Literal
|
||||||
|
|
||||||
_marc_version = '2022.4'
|
_marc_version = '2022.4'
|
||||||
_marc_root = '/opt/msc'
|
_marc_root = '/opt/msc'
|
||||||
|
@ -54,7 +55,7 @@ class Marc:
|
||||||
|
|
||||||
def submit_job(self, model: str, job: str,
|
def submit_job(self, model: str, job: str,
|
||||||
compile: bool = False,
|
compile: bool = False,
|
||||||
optimization: str = '',
|
optimization: Literal['', 'l', 'h'] = '',
|
||||||
env = None):
|
env = None):
|
||||||
"""
|
"""
|
||||||
Assemble command line arguments and call Marc executable.
|
Assemble command line arguments and call Marc executable.
|
||||||
|
@ -68,8 +69,8 @@ class Marc:
|
||||||
compile : bool, optional
|
compile : bool, optional
|
||||||
Compile DAMASK_Marc user subroutine (and save for future use).
|
Compile DAMASK_Marc user subroutine (and save for future use).
|
||||||
Defaults to False.
|
Defaults to False.
|
||||||
optimization : str, optional
|
optimization : {'', 'l', 'h'}, optional
|
||||||
Optimization level '' (-O0), 'l' (-O1), or 'h' (-O3).
|
Optimization level '': -O0, 'l': -O1, or 'h': -O3.
|
||||||
Defaults to ''.
|
Defaults to ''.
|
||||||
env : dict, optional
|
env : dict, optional
|
||||||
Environment for execution.
|
Environment for execution.
|
||||||
|
|
|
@ -8,8 +8,9 @@ import shlex as _shlex
|
||||||
import re as _re
|
import re as _re
|
||||||
import signal as _signal
|
import signal as _signal
|
||||||
import fractions as _fractions
|
import fractions as _fractions
|
||||||
from collections import abc as _abc
|
from collections import abc as _abc, OrderedDict as _OrderedDict
|
||||||
from functools import reduce as _reduce, partial as _partial
|
from functools import reduce as _reduce, partial as _partial, wraps as _wraps
|
||||||
|
import inspect
|
||||||
from typing import Optional as _Optional, Callable as _Callable, Union as _Union, Iterable as _Iterable, \
|
from typing import Optional as _Optional, Callable as _Callable, Union as _Union, Iterable as _Iterable, \
|
||||||
Dict as _Dict, List as _List, Tuple as _Tuple, Literal as _Literal, \
|
Dict as _Dict, List as _List, Tuple as _Tuple, Literal as _Literal, \
|
||||||
Any as _Any, TextIO as _TextIO
|
Any as _Any, TextIO as _TextIO
|
||||||
|
@ -540,10 +541,11 @@ def shapeblender(a: _Tuple[int, ...],
|
||||||
|
|
||||||
|
|
||||||
def _docstringer(docstring: _Union[str, _Callable],
|
def _docstringer(docstring: _Union[str, _Callable],
|
||||||
extra_parameters: _Optional[str] = None,
|
adopted_parameters: _Union[None, str, _Callable] = None,
|
||||||
# extra_examples: _Optional[str] = None,
|
adopted_return: _Union[None, str, _Callable] = None,
|
||||||
# extra_notes: _Optional[str] = None,
|
adopted_notes: _Union[None, str, _Callable] = None,
|
||||||
return_type: _Union[None, str, _Callable] = None) -> str:
|
adopted_examples: _Union[None, str, _Callable] = None,
|
||||||
|
adopted_references: _Union[None, str, _Callable] = None) -> str:
|
||||||
"""
|
"""
|
||||||
Extend a docstring.
|
Extend a docstring.
|
||||||
|
|
||||||
|
@ -551,50 +553,85 @@ def _docstringer(docstring: _Union[str, _Callable],
|
||||||
----------
|
----------
|
||||||
docstring : str or callable, optional
|
docstring : str or callable, optional
|
||||||
Docstring (of callable) to extend.
|
Docstring (of callable) to extend.
|
||||||
extra_parameters : str, optional
|
adopted_* : str or callable, optional
|
||||||
Additional information to append to Parameters section.
|
Additional information to insert into/append to respective section.
|
||||||
return_type : str or callable, optional
|
|
||||||
Type of return variable.
|
Notes
|
||||||
|
-----
|
||||||
|
adopted_return fetches the typehint of a passed function instead of the docstring
|
||||||
|
|
||||||
"""
|
"""
|
||||||
docstring_ = str( docstring if isinstance(docstring,str)
|
docstring_: str = str( docstring if isinstance(docstring,str)
|
||||||
else docstring.__doc__ if hasattr(docstring,'__doc__')
|
else docstring.__doc__ if callable(docstring) and docstring.__doc__
|
||||||
else '')
|
else '').rstrip()+'\n'
|
||||||
d = dict(Parameters=extra_parameters,
|
sections = _OrderedDict(
|
||||||
# Examples=extra_examples,
|
Parameters=adopted_parameters,
|
||||||
# Notes=extra_notes,
|
Returns=adopted_return,
|
||||||
)
|
Examples=adopted_examples,
|
||||||
for key,extra in [(k,v) for (k,v) in d.items() if v is not None]:
|
Notes=adopted_notes,
|
||||||
if not (heading := _re.search(fr'^([ ]*){key}\s*\n\1{"-"*len(key)}',
|
References=adopted_references)
|
||||||
docstring_,flags=_re.MULTILINE)):
|
|
||||||
raise RuntimeError(f"Docstring {docstring_} lacks a correctly formatted {key} section to insert values into")
|
|
||||||
content = [line for line in extra.split('\n') if line.strip()]
|
|
||||||
indent = len(heading.group(1))
|
|
||||||
shift = min([len(line)-len(line.lstrip(' '))-indent for line in content])
|
|
||||||
extra = '\n'.join([(line[shift:] if shift > 0 else
|
|
||||||
f'{" "*-shift}{line}') for line in content])
|
|
||||||
docstring_ = _re.sub(fr'(^([ ]*){key}\s*\n\2{"-"*len(key)}[\n ]*[A-Za-z0-9_ ]*: ([^\n]+\n)*)',
|
|
||||||
fr'\1{extra}\n',
|
|
||||||
docstring_,flags=_re.MULTILINE)
|
|
||||||
|
|
||||||
if return_type is None:
|
for i, (key, adopted) in [(i,(k,v)) for (i,(k,v)) in enumerate(sections.items()) if v is not None]:
|
||||||
return docstring_
|
section_regex = fr'^([ ]*){key}\s*\n\1*{"-"*len(key)}\s*\n'
|
||||||
else:
|
if key=='Returns':
|
||||||
if isinstance(return_type,str):
|
if callable(adopted):
|
||||||
return_type_ = return_type
|
return_class = adopted.__annotations__.get('return','')
|
||||||
|
return_type_ = (_sys.modules[adopted.__module__].__name__.split('.')[0]
|
||||||
|
+'.'
|
||||||
|
+(return_class.__name__ if not isinstance(return_class,str) else return_class))
|
||||||
|
else:
|
||||||
|
return_type_ = adopted
|
||||||
|
docstring_ = _re.sub(fr'(^[ ]*{key}\s*\n\s*{"-"*len(key)}\s*\n[ ]*[A-Za-z0-9_ ]*: )(.*)\n',
|
||||||
|
fr'\1{return_type_}\n',
|
||||||
|
docstring_,flags=_re.MULTILINE)
|
||||||
else:
|
else:
|
||||||
return_class = return_type.__annotations__.get('return','')
|
section_content_regex = fr'{section_regex}(?P<content>.*?)\n *(\n|\Z)'
|
||||||
return_type_ = (_sys.modules[return_type.__module__].__name__.split('.')[0]
|
adopted_: str = adopted.__doc__ if callable(adopted) else adopted #type: ignore
|
||||||
+'.'
|
try:
|
||||||
+(return_class.__name__ if not isinstance(return_class,str) else return_class)
|
if _re.search(fr'{section_regex}', adopted_, flags=_re.MULTILINE):
|
||||||
)
|
adopted_ = _re.search(section_content_regex, #type: ignore
|
||||||
|
adopted_,
|
||||||
|
flags=_re.MULTILINE|_re.DOTALL).group('content')
|
||||||
|
except AttributeError:
|
||||||
|
raise RuntimeError(f"Function docstring passed for docstring section '{key}' is invalid:\n{docstring}")
|
||||||
|
|
||||||
|
docstring_indent, adopted_indent = (min([len(line)-len(line.lstrip()) for line in section.split('\n') if line.strip()])
|
||||||
|
for section in [docstring_, adopted_])
|
||||||
|
shift = adopted_indent - docstring_indent
|
||||||
|
adopted_content = '\n'.join([(line[shift:] if shift > 0 else
|
||||||
|
f'{" "*-shift}{line}') for line in adopted_.split('\n') if line.strip()])
|
||||||
|
|
||||||
|
if _re.search(section_regex, docstring_, flags=_re.MULTILINE):
|
||||||
|
docstring_section_content = _re.search(section_content_regex, # type: ignore
|
||||||
|
docstring_,
|
||||||
|
flags=_re.MULTILINE|_re.DOTALL).group('content')
|
||||||
|
a_items, d_items = (_re.findall('^[ ]*([A-Za-z0-9_ ]*?)[ ]*:',content,flags=_re.MULTILINE)
|
||||||
|
for content in [adopted_content,docstring_section_content])
|
||||||
|
for item in a_items:
|
||||||
|
if item in d_items:
|
||||||
|
adopted_content = _re.sub(fr'^([ ]*){item}.*?(?:(\n)\1([A-Za-z0-9_])|([ ]*\Z))',
|
||||||
|
r'\1\3',
|
||||||
|
adopted_content,
|
||||||
|
flags=_re.MULTILINE|_re.DOTALL).rstrip(' \n')
|
||||||
|
docstring_ = _re.sub(fr'(^[ ]*{key}\s*\n\s*{"-"*len(key)}\s*\n.*?)\n *(\Z|\n)',
|
||||||
|
fr'\1\n{adopted_content}\n\2',
|
||||||
|
docstring_,
|
||||||
|
flags=_re.MULTILINE|_re.DOTALL)
|
||||||
|
else:
|
||||||
|
section_title = f'{" "*(shift+docstring_indent)}{key}\n{" "*(shift+docstring_indent)}{"-"*len(key)}\n'
|
||||||
|
section_matches = [_re.search(
|
||||||
|
fr'[ ]*{list(sections.keys())[index]}\s*\n\s*{"-"*len(list(sections.keys())[index])}\s*', docstring_)
|
||||||
|
for index in range(i,len(sections))]
|
||||||
|
subsequent_section = '\\Z' if not any(section_matches) else \
|
||||||
|
'\n'+next(item for item in section_matches if item is not None).group(0)
|
||||||
|
docstring_ = _re.sub(fr'({subsequent_section})',
|
||||||
|
fr'\n{section_title}{adopted_content}\n\1',
|
||||||
|
docstring_)
|
||||||
|
return docstring_
|
||||||
|
|
||||||
return _re.sub(r'(^([ ]*)Returns\s*\n\2-------\s*\n[ ]*[A-Za-z0-9_ ]*: )(.*)\n',
|
|
||||||
fr'\1{return_type_}\n',
|
|
||||||
docstring_,flags=_re.MULTILINE)
|
|
||||||
|
|
||||||
def extend_docstring(docstring: _Union[None, str, _Callable] = None,
|
def extend_docstring(docstring: _Union[None, str, _Callable] = None,
|
||||||
extra_parameters: _Optional[str] = None) -> _Callable:
|
**kwargs) -> _Callable:
|
||||||
"""
|
"""
|
||||||
Decorator: Extend the function's docstring.
|
Decorator: Extend the function's docstring.
|
||||||
|
|
||||||
|
@ -602,8 +639,8 @@ def extend_docstring(docstring: _Union[None, str, _Callable] = None,
|
||||||
----------
|
----------
|
||||||
docstring : str or callable, optional
|
docstring : str or callable, optional
|
||||||
Docstring to extend. Defaults to that of decorated function.
|
Docstring to extend. Defaults to that of decorated function.
|
||||||
extra_parameters : str, optional
|
adopted_* : str or callable, optional
|
||||||
Additional information to append to Parameters section.
|
Additional information to insert into/append to respective section.
|
||||||
|
|
||||||
Notes
|
Notes
|
||||||
-----
|
-----
|
||||||
|
@ -611,13 +648,55 @@ def extend_docstring(docstring: _Union[None, str, _Callable] = None,
|
||||||
|
|
||||||
"""
|
"""
|
||||||
def _decorator(func):
|
def _decorator(func):
|
||||||
|
if 'adopted_return' not in kwargs: kwargs['adopted_return'] = func
|
||||||
func.__doc__ = _docstringer(func.__doc__ if docstring is None else docstring,
|
func.__doc__ = _docstringer(func.__doc__ if docstring is None else docstring,
|
||||||
extra_parameters,
|
**kwargs)
|
||||||
func if isinstance(docstring,_Callable) else None,
|
|
||||||
)
|
|
||||||
return func
|
return func
|
||||||
return _decorator
|
return _decorator
|
||||||
|
|
||||||
|
def pass_on(keyword: str,
|
||||||
|
target: _Callable,
|
||||||
|
wrapped: _Callable = None) -> _Callable: # type: ignore
|
||||||
|
"""
|
||||||
|
Decorator: Combine signatures of 'wrapped' and 'target' functions and pass on output of 'target' as 'keyword' argument.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
keyword : str
|
||||||
|
Keyword added to **kwargs of the decorated function
|
||||||
|
passing on the result of 'target'.
|
||||||
|
target : callable
|
||||||
|
The output of this function is passed to the
|
||||||
|
decorated function as 'keyword' argument.
|
||||||
|
wrapped: callable, optional
|
||||||
|
Signature of 'wrapped' function combined with
|
||||||
|
that of 'target' yields the overall signature of decorated function.
|
||||||
|
|
||||||
|
Notes
|
||||||
|
-----
|
||||||
|
The keywords used by 'target' will be prioritized
|
||||||
|
if they overlap with those of the decorated function.
|
||||||
|
Functions 'target' and 'wrapped' are assumed to only have keyword arguments.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
def decorator(func):
|
||||||
|
@_wraps(func)
|
||||||
|
def wrapper(*args, **kwargs):
|
||||||
|
kw_wrapped = set(kwargs.keys()) - set(inspect.getfullargspec(target).args)
|
||||||
|
kwargs_wrapped = {kw: kwargs.pop(kw) for kw in kw_wrapped}
|
||||||
|
kwargs_wrapped[keyword] = target(**kwargs)
|
||||||
|
return func(*args, **kwargs_wrapped)
|
||||||
|
args_ = [] if wrapped is None or 'self' not in inspect.signature(wrapped).parameters \
|
||||||
|
else [inspect.signature(wrapped).parameters['self']]
|
||||||
|
for f in [target] if wrapped is None else [target,wrapped]:
|
||||||
|
for param in inspect.signature(f).parameters.values():
|
||||||
|
if param.name != keyword \
|
||||||
|
and param.name not in [p.name for p in args_]+['self','cls', 'args', 'kwargs']:
|
||||||
|
args_.append(param.replace(kind=inspect._ParameterKind.KEYWORD_ONLY))
|
||||||
|
wrapper.__signature__ = inspect.Signature(parameters=args_,return_annotation=inspect.signature(func).return_annotation)
|
||||||
|
return wrapper
|
||||||
|
return decorator
|
||||||
|
|
||||||
def DREAM3D_base_group(fname: _Union[str, _Path]) -> str:
|
def DREAM3D_base_group(fname: _Union[str, _Path]) -> str:
|
||||||
"""
|
"""
|
||||||
|
@ -800,7 +879,7 @@ class ProgressBar:
|
||||||
prefix: str,
|
prefix: str,
|
||||||
bar_length: int):
|
bar_length: int):
|
||||||
"""
|
"""
|
||||||
Set current time as basis for ETA estimation.
|
New progress bar.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
|
|
|
@ -4,7 +4,7 @@ warn_redundant_casts = True
|
||||||
ignore_missing_imports = True
|
ignore_missing_imports = True
|
||||||
[mypy-h5py.*]
|
[mypy-h5py.*]
|
||||||
ignore_missing_imports = True
|
ignore_missing_imports = True
|
||||||
[mypy-vtk.*]
|
[mypy-vtkmodules.*]
|
||||||
ignore_missing_imports = True
|
ignore_missing_imports = True
|
||||||
[mypy-PIL.*]
|
[mypy-PIL.*]
|
||||||
ignore_missing_imports = True
|
ignore_missing_imports = True
|
||||||
|
|
|
@ -26,4 +26,3 @@ install_requires =
|
||||||
vtk>=8.1
|
vtk>=8.1
|
||||||
matplotlib>=3.0 # requires numpy, pillow
|
matplotlib>=3.0 # requires numpy, pillow
|
||||||
pyyaml>=3.12
|
pyyaml>=3.12
|
||||||
setup_requires = setuptools
|
|
||||||
|
|
|
@ -60,9 +60,9 @@ def update(request):
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def ref_path_base():
|
def res_path_base():
|
||||||
"""Directory containing reference results."""
|
"""Directory containing testing resources."""
|
||||||
return Path(__file__).parent/'reference'
|
return Path(__file__).parent/'resources'
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -1 +0,0 @@
|
||||||
27972d6a0955e4e6e27a6ac5762abda8
|
|
|
@ -1 +0,0 @@
|
||||||
dd71d25ccb52c3fdfd2ab727fc852a98
|
|
Before Width: | Height: | Size: 147 B After Width: | Height: | Size: 147 B |
Before Width: | Height: | Size: 138 B After Width: | Height: | Size: 138 B |
|
@ -0,0 +1 @@
|
||||||
|
n10-id1_scaled.vtk binary
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue