diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index b7f7f8b0b..ca1b2959a 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -60,11 +60,11 @@ variables: MPI_Intel: "$IMPI2020Intel19_1" MPI_GNU: "$OMPI4_0GNU10" # ++++++++++++ PETSc ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - PETSc3_14_0IMPI2020Intel19_1: "Libraries/PETSc/3.14.0/Intel-19.1.2-IntelMPI-2019" - PETSc3_14_0OMPI4_0GNU10: "Libraries/PETSc/3.14.0/GNU-10-OpenMPI-4.0.5" + PETSc3_14_2IMPI2020Intel19_1: "Libraries/PETSc/3.14.2/Intel-19.1.2-IntelMPI-2019" + PETSc3_14_2OMPI4_0GNU10: "Libraries/PETSc/3.14.2/GNU-10-OpenMPI-4.0.5" # ------------ Defaults ---------------------------------------------- - PETSc_Intel: "$PETSc3_14_0IMPI2020Intel19_1" - PETSc_GNU: "$PETSc3_14_0OMPI4_0GNU10" + PETSc_Intel: "$PETSc3_14_2IMPI2020Intel19_1" + PETSc_GNU: "$PETSc3_14_2OMPI4_0GNU10" # ++++++++++++ commercial FEM ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ MSC2020: "FEM/MSC/2020" # ------------ Defaults ---------------------------------------------- @@ -262,20 +262,6 @@ Pytest_grid: - master - release -Thermal: - stage: grid - script: Thermal/test.py - except: - - master - - release - -Nonlocal_Damage_DetectChanges: - stage: grid - script: Nonlocal_Damage_DetectChanges/test.py - except: - - master - - release - Plasticity_DetectChanges: stage: grid script: Plasticity_DetectChanges/test.py @@ -353,7 +339,6 @@ backupData: - mkdir $BACKUP/${CI_PIPELINE_ID}_${CI_COMMIT_SHA} - mv $LOCAL_HOME/performance/time.png $BACKUP/${CI_PIPELINE_ID}_${CI_COMMIT_SHA}/ - mv $LOCAL_HOME/performance/memory.png $BACKUP/${CI_PIPELINE_ID}_${CI_COMMIT_SHA}/ - - mv $DAMASKROOT/PRIVATE/documenting/DAMASK_* $BACKUP/${CI_PIPELINE_ID}_${CI_COMMIT_SHA}/ only: - development diff --git a/.gitmodules b/.gitmodules index 5d17eb0cb..0587fff4c 100644 --- a/.gitmodules +++ b/.gitmodules @@ -2,3 +2,4 @@ path = PRIVATE url = ../PRIVATE.git branch = master + shallow = true diff --git a/CMakeLists.txt b/CMakeLists.txt index dd2348fd1..198528b59 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,18 @@ -######################################################################################## -# Compiler options for building DAMASK -cmake_minimum_required (VERSION 3.10.0 FATAL_ERROR) +cmake_minimum_required (VERSION 3.10.0) +include (FindPkgConfig REQUIRED) + +# Dummy project to determine compiler names and version +project (Prerequisites LANGUAGES) +set(ENV{PKG_CONFIG_PATH} "$ENV{PETSC_DIR}/$ENV{PETSC_ARCH}/lib/pkgconfig") +pkg_check_modules (PETSC REQUIRED PETSc>=3.12.0 PETSc<3.15.0) +pkg_get_variable (CMAKE_Fortran_COMPILER PETSc fcompiler) +pkg_get_variable (CMAKE_C_COMPILER PETSc ccompiler) + +find_program (CAT_EXECUTABLE NAMES cat) +execute_process (COMMAND ${CAT_EXECUTABLE} ${PROJECT_SOURCE_DIR}/VERSION + RESULT_VARIABLE DAMASK_VERSION_RETURN + OUTPUT_VARIABLE DAMASK_VERSION + OUTPUT_STRIP_TRAILING_WHITESPACE) #--------------------------------------------------------------------------------------- # Find PETSc from system environment @@ -28,19 +40,10 @@ include ${petsc_conf_rules} include ${petsc_conf_variables} INCLUDE_DIRS := \${PETSC_FC_INCLUDES} LIBRARIES := \${PETSC_WITH_EXTERNAL_LIB} -COMPILERF := \${FC} -COMPILERC := \${CC} -LINKERNAME := \${FLINKER} includes: \t@echo \${INCLUDE_DIRS} extlibs: \t@echo \${LIBRARIES} -compilerf: -\t@echo \${COMPILERF} -compilerc: -\t@echo \${COMPILERC} -linker: -\t@echo \${LINKERNAME} ") # CMake will execute each target in the ${petsc_config_makefile} @@ -52,26 +55,10 @@ execute_process (COMMAND ${MAKE_EXECUTABLE} --no-print-directory -f ${petsc_conf OUTPUT_VARIABLE petsc_includes OUTPUT_STRIP_TRAILING_WHITESPACE) # Find the PETSc external linking directory settings -# required for final linking, must be appended after the executable execute_process (COMMAND ${MAKE_EXECUTABLE} --no-print-directory -f ${petsc_config_makefile} "extlibs" RESULT_VARIABLE PETSC_EXTERNAL_LIB_RETURN OUTPUT_VARIABLE petsc_external_lib OUTPUT_STRIP_TRAILING_WHITESPACE) -# PETSc specified fortran compiler -execute_process (COMMAND ${MAKE_EXECUTABLE} --no-print-directory -f ${petsc_config_makefile} "compilerf" - RESULT_VARIABLE PETSC_MPIFC_RETURN - OUTPUT_VARIABLE PETSC_MPIFC - OUTPUT_STRIP_TRAILING_WHITESPACE) -# PETSc specified C compiler -execute_process (COMMAND ${MAKE_EXECUTABLE} --no-print-directory -f ${petsc_config_makefile} "compilerc" - RESULT_VARIABLE PETSC_MPICC_RETURN - OUTPUT_VARIABLE PETSC_MPICC - OUTPUT_STRIP_TRAILING_WHITESPACE) -# PETSc specified linker (Fortran compiler + PETSc linking flags) -execute_process (COMMAND ${MAKE_EXECUTABLE} --no-print-directory -f ${petsc_config_makefile} "linker" - RESULT_VARIABLE PETSC_LINKER_RETURN - OUTPUT_VARIABLE PETSC_LINKER - OUTPUT_STRIP_TRAILING_WHITESPACE) # Remove temporary makefile, no need to keep it anymore. file (REMOVE_RECURSE ${TEMPDIR}) @@ -90,14 +77,6 @@ endforeach (exlib) message ("Found PETSC_DIR:\n${PETSC_DIR}\n" ) message ("Found PETSC_INCLUDES:\n${PETSC_INCLUDES}\n" ) message ("Found PETSC_EXTERNAL_LIB:\n${PETSC_EXTERNAL_LIB}\n") -message ("Found PETSC_LINKER:\n${PETSC_LINKER}\n" ) -message ("Found MPI Fortran Compiler:\n${PETSC_MPIFC}\n" ) -message ("Found MPI C Compiler:\n${PETSC_MPICC}\n" ) - -# set compiler commands to match PETSc (needs to be done before defining the project) -# https://cmake.org/Wiki/CMake_FAQ#How_do_I_use_a_different_compiler.3F -set (CMAKE_Fortran_COMPILER "${PETSC_MPIFC}") -set (CMAKE_C_COMPILER "${PETSC_MPICC}") #--------------------------------------------------------------------------------------- # Now start to care about DAMASK @@ -105,17 +84,18 @@ set (CMAKE_C_COMPILER "${PETSC_MPICC}") # DAMASK solver defines project to build string(TOLOWER ${DAMASK_SOLVER} DAMASK_SOLVER) if (DAMASK_SOLVER STREQUAL "grid") - project (damask-grid Fortran C) + project (damask-grid HOMEPAGE_URL https://damask.mpie.de LANGUAGES Fortran C) add_definitions (-DGrid) - message ("Building Grid Solver\n") elseif (DAMASK_SOLVER STREQUAL "mesh") - project (damask-mesh Fortran C) + project (damask-mesh HOMEPAGE_URL https://damask.mpie.de LANGUAGES Fortran C) add_definitions (-DMesh) - message ("Building Mesh Solver\n") else () message (FATAL_ERROR "Build target (DAMASK_SOLVER) is not defined") endif () -list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake) +add_definitions (-DDAMASKVERSION="${DAMASK_VERSION}") +add_definitions (-DPETSc) + +message ("\nBuilding ${CMAKE_PROJECT_NAME}\n") if (CMAKE_BUILD_TYPE STREQUAL "") set (CMAKE_BUILD_TYPE "RELEASE") @@ -153,17 +133,8 @@ if (CMAKE_BUILD_TYPE STREQUAL "SYNTAXONLY") set (BUILDCMD_POST "${BUILDCMD_POST} -fsyntax-only") endif () -# Parse DAMASK version from VERSION file -find_program (CAT_EXECUTABLE NAMES cat) -execute_process (COMMAND ${CAT_EXECUTABLE} ${PROJECT_SOURCE_DIR}/VERSION - RESULT_VARIABLE DAMASK_VERSION_RETURN - OUTPUT_VARIABLE DAMASK_V - OUTPUT_STRIP_TRAILING_WHITESPACE) -add_definitions (-DDAMASKVERSION="${DAMASK_V}") - -# definition of other macros -add_definitions (-DPETSc) +list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake) if (CMAKE_Fortran_COMPILER_ID STREQUAL "Intel") include (Compiler-Intel) elseif(CMAKE_Fortran_COMPILER_ID STREQUAL "GNU") @@ -174,9 +145,8 @@ else () message (FATAL_ERROR "Compiler type (CMAKE_Fortran_COMPILER_ID) not recognized") endif () - set (CMAKE_Fortran_FLAGS_${CMAKE_BUILD_TYPE} "${BUILDCMD_PRE} ${OPENMP_FLAGS} ${STANDARD_CHECK} ${OPTIMIZATION_FLAGS} ${COMPILE_FLAGS} ${PRECISION_FLAGS}") -set (CMAKE_Fortran_LINK_EXECUTABLE "${BUILDCMD_PRE} ${PETSC_LINKER} ${OPENMP_FLAGS} ${OPTIMIZATION_FLAGS} ${LINKER_FLAGS}") +set (CMAKE_Fortran_LINK_EXECUTABLE "${BUILDCMD_PRE} ${CMAKE_Fortran_COMPILER} ${OPENMP_FLAGS} ${OPTIMIZATION_FLAGS} ${LINKER_FLAGS}") if (CMAKE_BUILD_TYPE STREQUAL "DEBUG") set (CMAKE_Fortran_FLAGS_${CMAKE_BUILD_TYPE} "${CMAKE_Fortran_FLAGS_${CMAKE_BUILD_TYPE}} ${DEBUG_FLAGS}") diff --git a/Makefile b/Makefile index 418d70507..102b954bd 100644 --- a/Makefile +++ b/Makefile @@ -2,27 +2,20 @@ SHELL = /bin/sh ######################################################################################## # Makefile for the installation of DAMASK ######################################################################################## -DAMASK_ROOT = $(shell python3 -c "import os,sys; print(os.path.normpath(os.path.realpath(os.path.expanduser('$(pwd)'))))") .PHONY: all all: grid mesh processing .PHONY: grid -grid: build/grid - @(cd build/grid;make -j${DAMASK_NUM_THREADS} all install;) +grid: + @cmake -B build/grid -DDAMASK_SOLVER=GRID -DCMAKE_INSTALL_PREFIX=${PWD} -DCMAKE_BUILD_TYPE=${BUILD_TYPE} -DBUILDCMD_POST=${BUILDCMD_POST} -DBUILDCMD_PRE=${BUILDCMD_PRE} -DOPTIMIZATION=${OPTIMIZATION} -DOPENMP=${OPENMP} + @cmake --build build/grid --parallel ${DAMASK_NUM_THRADS} + @cmake --install build/grid .PHONY: mesh -mesh: build/mesh - @(cd build/mesh; make -j${DAMASK_NUM_THREADS} all install;) - -.PHONY: build/grid -build/grid: - @mkdir -p build/grid - @(cd build/grid; cmake -Wno-dev -DDAMASK_SOLVER=GRID -DCMAKE_INSTALL_PREFIX=${DAMASK_ROOT} -DCMAKE_BUILD_TYPE=${BUILD_TYPE} -DBUILDCMD_POST=${BUILDCMD_POST} -DBUILDCMD_PRE=${BUILDCMD_PRE} -DOPTIMIZATION=${OPTIMIZATION} -DOPENMP=${OPENMP} ../../;) - -.PHONY: build/mesh -build/mesh: - @mkdir -p build/mesh - @(cd build/mesh; cmake -Wno-dev -DDAMASK_SOLVER=MESH -DCMAKE_INSTALL_PREFIX=${DAMASK_ROOT} -DCMAKE_BUILD_TYPE=${BUILD_TYPE} -DBUILDCMD_POST=${BUILDCMD_POST} -DBUILDCMD_PRE=${BUILDCMD_PRE} -DOPTIMIZATION=${OPTIMIZATION} -DOPENMP=${OPENMP} ../../;) +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 --build build/mesh --parallel ${DAMASK_NUM_THRADS} + @cmake --install build/mesh .PHONY: clean clean: diff --git a/VERSION b/VERSION index d04d76024..c6d828650 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -v3.0.0-alpha-920-gccf1a849f +v3.0.0-alpha2-153-gf8dd5df0c diff --git a/cmake/Compiler-Intel.cmake b/cmake/Compiler-Intel.cmake index 719ed885b..5b551069e 100644 --- a/cmake/Compiler-Intel.cmake +++ b/cmake/Compiler-Intel.cmake @@ -20,7 +20,7 @@ endif () # -assume std_mod_proc_name (included in -standard-semantics) causes problems if other modules # (PETSc, HDF5) are not compiled with this option (https://software.intel.com/en-us/forums/intel-fortran-compiler-for-linux-and-mac-os-x/topic/62172) -set (STANDARD_CHECK "-stand f15 -standard-semantics -assume nostd_mod_proc_name") +set (STANDARD_CHECK "-stand f18 -standard-semantics -assume nostd_mod_proc_name") set (LINKER_FLAGS "${LINKER_FLAGS} -shared-intel") # Link against shared Intel libraries instead of static ones diff --git a/examples/FEM/polyXtal/material.yaml b/examples/FEM/polyXtal/material.yaml index c7d17657d..333073150 100644 --- a/examples/FEM/polyXtal/material.yaml +++ b/examples/FEM/polyXtal/material.yaml @@ -5,8 +5,8 @@ homogenization: phase: Aluminum: + lattice: cF mechanics: - lattice: cF output: [F, P, F_e, F_p, L_p] elasticity: {C_11: 106.75e9, C_12: 60.41e9, C_44: 28.34e9, type: hooke} plasticity: diff --git a/processing/post/DADF5_postResults.py b/processing/post/DADF5_postResults.py index be4f78569..a1b162e3d 100755 --- a/processing/post/DADF5_postResults.py +++ b/processing/post/DADF5_postResults.py @@ -33,12 +33,12 @@ for filename in options.filenames: results = damask.Result(filename) if not results.structured: continue - coords = damask.grid_filters.cell_coord0(results.grid,results.size,results.origin).reshape(-1,3,order='F') + coords = damask.grid_filters.coordinates0_point(results.cells,results.size,results.origin).reshape(-1,3,order='F') N_digits = int(np.floor(np.log10(int(results.increments[-1][3:]))))+1 N_digits = 5 # hack to keep test intact for inc in damask.util.show_progress(results.iterate('increments'),len(results.increments)): - table = damask.Table(np.ones(np.product(results.grid),dtype=int)*int(inc[3:]),{'inc':(1,)})\ + table = damask.Table(np.ones(np.product(results.cells),dtype=int)*int(inc[3:]),{'inc':(1,)})\ .add('pos',coords.reshape(-1,3)) results.pick('homogenizations',False) @@ -46,14 +46,14 @@ for filename in options.filenames: for label in options.con: x = results.get_dataset_location(label) if len(x) != 0: - table = table.add(label,results.read_dataset(x,0,plain=True).reshape(results.grid.prod(),-1)) + table = table.add(label,results.read_dataset(x,0,plain=True).reshape(results.cells.prod(),-1)) results.pick('phases',False) results.pick('homogenizations',True) for label in options.mat: x = results.get_dataset_location(label) if len(x) != 0: - table = table.add(label,results.read_dataset(x,0,plain=True).reshape(results.grid.prod(),-1)) + table = table.add(label,results.read_dataset(x,0,plain=True).reshape(results.cells.prod(),-1)) dirname = os.path.abspath(os.path.join(os.path.dirname(filename),options.dir)) if not os.path.isdir(dirname): diff --git a/processing/post/addCompatibilityMismatch.py b/processing/post/addCompatibilityMismatch.py index 1b4425e06..d06eca72e 100755 --- a/processing/post/addCompatibilityMismatch.py +++ b/processing/post/addCompatibilityMismatch.py @@ -71,13 +71,13 @@ for name in filenames: damask.util.report(scriptName,name) table = damask.Table.load(StringIO(''.join(sys.stdin.read())) if name is None else name) - grid,size,origin = damask.grid_filters.cell_coord0_gridSizeOrigin(table.get(options.pos)) + grid,size,origin = damask.grid_filters.cellsSizeOrigin_coordinates0_point(table.get(options.pos)) F = table.get(options.defgrad).reshape(tuple(grid)+(-1,),order='F').reshape(tuple(grid)+(3,3)) - nodes = damask.grid_filters.node_coord(size,F) + nodes = damask.grid_filters.coordinates_node(size,F) if options.shape: - centers = damask.grid_filters.cell_coord(size,F) + centers = damask.grid_filters.coordinates_point(size,F) shapeMismatch = shapeMismatch(size,F,nodes,centers) table = table.add('shapeMismatch(({}))'.format(options.defgrad), shapeMismatch.reshape(-1,1,order='F'), diff --git a/processing/post/addCurl.py b/processing/post/addCurl.py index d91c2be92..2e45631e7 100755 --- a/processing/post/addCurl.py +++ b/processing/post/addCurl.py @@ -44,7 +44,7 @@ for name in filenames: damask.util.report(scriptName,name) table = damask.Table.load(StringIO(''.join(sys.stdin.read())) if name is None else name) - grid,size,origin = damask.grid_filters.cell_coord0_gridSizeOrigin(table.get(options.pos)) + grid,size,origin = damask.grid_filters.cellsSizeOrigin_coordinates0_point(table.get(options.pos)) for label in options.labels: field = table.get(label) diff --git a/processing/post/addDisplacement.py b/processing/post/addDisplacement.py index c3ba4a8af..6fe577ec7 100755 --- a/processing/post/addDisplacement.py +++ b/processing/post/addDisplacement.py @@ -48,24 +48,24 @@ for name in filenames: damask.util.report(scriptName,name) table = damask.Table.load(StringIO(''.join(sys.stdin.read())) if name is None else name) - grid,size,origin = damask.grid_filters.cell_coord0_gridSizeOrigin(table.get(options.pos)) + grid,size,origin = damask.grid_filters.cellsSizeOrigin_coordinates0_point(table.get(options.pos)) F = table.get(options.f).reshape(tuple(grid)+(-1,),order='F').reshape(tuple(grid)+(3,3)) if options.nodal: - damask.Table(damask.grid_filters.node_coord0(grid,size).reshape(-1,3,order='F'), + damask.Table(damask.grid_filters.coordinates0_node(grid,size).reshape(-1,3,order='F'), {'pos':(3,)})\ .add('avg({}).{}'.format(options.f,options.pos), - damask.grid_filters.node_displacement_avg(size,F).reshape(-1,3,order='F'), + damask.grid_filters.displacement_avg_node(size,F).reshape(-1,3,order='F'), scriptID+' '+' '.join(sys.argv[1:]))\ .add('fluct({}).{}'.format(options.f,options.pos), - damask.grid_filters.node_displacement_fluct(size,F).reshape(-1,3,order='F'), + damask.grid_filters.displacement_fluct_node(size,F).reshape(-1,3,order='F'), scriptID+' '+' '.join(sys.argv[1:]))\ .save((sys.stdout if name is None else os.path.splitext(name)[0]+'_nodal.txt')) else: table.add('avg({}).{}'.format(options.f,options.pos), - damask.grid_filters.cell_displacement_avg(size,F).reshape(-1,3,order='F'), + damask.grid_filters.displacement_avg_point(size,F).reshape(-1,3,order='F'), scriptID+' '+' '.join(sys.argv[1:]))\ .add('fluct({}).{}'.format(options.f,options.pos), - damask.grid_filters.cell_displacement_fluct(size,F).reshape(-1,3,order='F'), + damask.grid_filters.displacement_fluct_point(size,F).reshape(-1,3,order='F'), scriptID+' '+' '.join(sys.argv[1:]))\ .save((sys.stdout if name is None else name)) diff --git a/processing/post/addDivergence.py b/processing/post/addDivergence.py index 6e5629285..25023e015 100755 --- a/processing/post/addDivergence.py +++ b/processing/post/addDivergence.py @@ -44,7 +44,7 @@ for name in filenames: damask.util.report(scriptName,name) table = damask.Table.load(StringIO(''.join(sys.stdin.read())) if name is None else name) - grid,size,origin = damask.grid_filters.cell_coord0_gridSizeOrigin(table.get(options.pos)) + grid,size,origin = damask.grid_filters.cellsSizeOrigin_coordinates0_point(table.get(options.pos)) for label in options.labels: field = table.get(label) diff --git a/processing/post/addEuclideanDistance.py b/processing/post/addEuclideanDistance.py index 0c18bdccc..86eb46ec7 100755 --- a/processing/post/addEuclideanDistance.py +++ b/processing/post/addEuclideanDistance.py @@ -143,7 +143,7 @@ for name in filenames: damask.util.report(scriptName,name) table = damask.Table.load(StringIO(''.join(sys.stdin.read())) if name is None else name) - grid,size,origin = damask.grid_filters.cell_coord0_gridSizeOrigin(table.get(options.pos)) + grid,size,origin = damask.grid_filters.cellsSizeOrigin_coordinates0_point(table.get(options.pos)) neighborhood = neighborhoods[options.neighborhood] diffToNeighbor = np.empty(list(grid+2)+[len(neighborhood)],'i') diff --git a/processing/post/addGradient.py b/processing/post/addGradient.py index 147773734..bd6173e6e 100755 --- a/processing/post/addGradient.py +++ b/processing/post/addGradient.py @@ -44,7 +44,7 @@ for name in filenames: damask.util.report(scriptName,name) table = damask.Table.load(StringIO(''.join(sys.stdin.read())) if name is None else name) - grid,size,origin = damask.grid_filters.cell_coord0_gridSizeOrigin(table.get(options.pos)) + grid,size,origin = damask.grid_filters.cellsSizeOrigin_coordinates0_point(table.get(options.pos)) for label in options.labels: field = table.get(label) diff --git a/processing/pre/geom_fromDREAM3D.py b/processing/pre/geom_fromDREAM3D.py index eb4fe443e..d51a2b51e 100755 --- a/processing/pre/geom_fromDREAM3D.py +++ b/processing/pre/geom_fromDREAM3D.py @@ -65,7 +65,7 @@ if filenames == []: parser.error('no input file specified.') for name in filenames: damask.util.report(scriptName,name) - geom = damask.Geom.load_DREAM3D(name,options.basegroup,options.pointwise) + geom = damask.Grid.load_DREAM3D(name,options.basegroup,options.pointwise) damask.util.croak(geom) geom.save_ASCII(os.path.splitext(name)[0]+'.geom') diff --git a/processing/pre/geom_fromOsteonGeometry.py b/processing/pre/geom_fromOsteonGeometry.py index 51aca3056..0bdf8aa7e 100755 --- a/processing/pre/geom_fromOsteonGeometry.py +++ b/processing/pre/geom_fromOsteonGeometry.py @@ -133,7 +133,7 @@ for i in range(3,np.max(microstructure)): header = [scriptID + ' ' + ' '.join(sys.argv[1:])]\ + config_header -geom = damask.Geom(microstructure.reshape(grid), +geom = damask.Grid(microstructure.reshape(grid), size,-size/2, comments=header) damask.util.croak(geom) diff --git a/processing/pre/geom_grainGrowth.py b/processing/pre/geom_grainGrowth.py index 5c751d662..23a46b668 100755 --- a/processing/pre/geom_grainGrowth.py +++ b/processing/pre/geom_grainGrowth.py @@ -62,9 +62,9 @@ if filenames == []: filenames = [None] for name in filenames: damask.util.report(scriptName,name) - geom = damask.Geom.load(StringIO(''.join(sys.stdin.read())) if name is None else name) + geom = damask.Grid.load(StringIO(''.join(sys.stdin.read())) if name is None else name) - grid_original = geom.grid + grid_original = geom.cells damask.util.croak(geom) material = np.tile(geom.material,np.where(grid_original == 1, 2,1)) # make one copy along dimensions with grid == 1 grid = np.array(material.shape) @@ -169,7 +169,7 @@ for name in filenames: # undo any changes involving immutable materials material = np.where(immutable, material_original,material) - damask.Geom(material = material[0:grid_original[0],0:grid_original[1],0:grid_original[2]], + damask.Grid(material = material[0:grid_original[0],0:grid_original[1],0:grid_original[2]], size = geom.size, origin = geom.origin, comments = geom.comments + [scriptID + ' ' + ' '.join(sys.argv[1:])], diff --git a/processing/pre/mentat_spectralBox.py b/processing/pre/mentat_spectralBox.py index d182a6d54..d2c966f3f 100755 --- a/processing/pre/mentat_spectralBox.py +++ b/processing/pre/mentat_spectralBox.py @@ -196,12 +196,12 @@ if filenames == []: filenames = [None] for name in filenames: damask.util.report(scriptName,name) - geom = damask.Geom.load(StringIO(''.join(sys.stdin.read())) if name is None else name) + geom = damask.Grid.load(StringIO(''.join(sys.stdin.read())) if name is None else name) material = geom.material.flatten(order='F') cmds = [\ init(), - mesh(geom.grid,geom.size), + mesh(geom.cells,geom.size), materials(), geometry(), initial_conditions(material), diff --git a/processing/pre/seeds_fromDistribution.py b/processing/pre/seeds_fromDistribution.py index 1f20db995..59d9f0213 100755 --- a/processing/pre/seeds_fromDistribution.py +++ b/processing/pre/seeds_fromDistribution.py @@ -91,7 +91,7 @@ class myThread (threading.Thread): perturbedSeedsTable.set('pos',coords).save(perturbedSeedsVFile,legacy=True) #--- do tesselation with perturbed seed file ------------------------------------------------------ - perturbedGeom = damask.Geom.from_Voronoi_tessellation(options.grid,np.ones(3),coords) + perturbedGeom = damask.Grid.from_Voronoi_tessellation(options.grid,np.ones(3),coords) #--- evaluate current seeds file ------------------------------------------------------------------ @@ -210,9 +210,9 @@ baseFile = os.path.splitext(os.path.basename(options.seedFile))[0] points = np.array(options.grid).prod().astype('float') # ----------- calculate target distribution and bin edges -targetGeom = damask.Geom.load_ASCII(os.path.splitext(os.path.basename(options.target))[0]+'.geom') +targetGeom = damask.Grid.load_ASCII(os.path.splitext(os.path.basename(options.target))[0]+'.geom') nMaterials = len(np.unique(targetGeom.material)) -targetVolFrac = np.bincount(targetGeom.material.flatten())/targetGeom.grid.prod().astype(np.float) +targetVolFrac = np.bincount(targetGeom.material.flatten())/targetGeom.cells.prod().astype(np.float) target = [] for i in range(1,nMaterials+1): targetHist,targetBins = np.histogram(targetVolFrac,bins=i) #bin boundaries @@ -229,7 +229,7 @@ bestSeedsUpdate = time.time() # ----------- tessellate initial seed file to get and evaluate geom file bestSeedsVFile.seek(0) -initialGeom = damask.Geom.from_Voronoi_tessellation(options.grid,np.ones(3),initial_seeds) +initialGeom = damask.Grid.from_Voronoi_tessellation(options.grid,np.ones(3),initial_seeds) if len(np.unique(targetGeom.material)) != nMaterials: damask.util.croak('error. Material count mismatch') diff --git a/processing/pre/seeds_fromPokes.py b/processing/pre/seeds_fromPokes.py index 67acf0f6b..e6eee809a 100755 --- a/processing/pre/seeds_fromPokes.py +++ b/processing/pre/seeds_fromPokes.py @@ -52,15 +52,15 @@ options.box = np.array(options.box).reshape(3,2) for name in filenames: damask.util.report(scriptName,name) - geom = damask.Geom.load_ASCII(StringIO(''.join(sys.stdin.read())) if name is None else name) + geom = damask.Grid.load_ASCII(StringIO(''.join(sys.stdin.read())) if name is None else name) - offset =(np.amin(options.box, axis=1)*geom.grid/geom.size).astype(int) + offset =(np.amin(options.box, axis=1)*geom.cells/geom.size).astype(int) box = np.amax(options.box, axis=1) \ - np.amin(options.box, axis=1) Nx = int(options.N/np.sqrt(options.N*geom.size[1]*box[1]/geom.size[0]/box[0])) Ny = int(options.N/np.sqrt(options.N*geom.size[0]*box[0]/geom.size[1]/box[1])) - Nz = int(box[2]*geom.grid[2]) + Nz = int(box[2]*geom.cells[2]) damask.util.croak('poking {} x {} x {} in box {} {} {}...'.format(Nx,Ny,Nz,*box)) @@ -70,12 +70,12 @@ for name in filenames: n = 0 for i in range(Nx): for j in range(Ny): - g[0] = round((i+0.5)*box[0]*geom.grid[0]/Nx-0.5)+offset[0] - g[1] = round((j+0.5)*box[1]*geom.grid[1]/Ny-0.5)+offset[1] + g[0] = round((i+0.5)*box[0]*geom.cells[0]/Nx-0.5)+offset[0] + g[1] = round((j+0.5)*box[1]*geom.cells[1]/Ny-0.5)+offset[1] for k in range(Nz): g[2] = k + offset[2] - g %= geom.grid - seeds[n,0:3] = (g+0.5)/geom.grid # normalize coordinates to box + g %= geom.cells + seeds[n,0:3] = (g+0.5)/geom.cells # normalize coordinates to box seeds[n, 3] = geom.material[g[0],g[1],g[2]] if options.x: g[0] += 1 if options.y: g[1] += 1 @@ -85,7 +85,7 @@ for name in filenames: comments = geom.comments \ + [scriptID + ' ' + ' '.join(sys.argv[1:]), 'poking\ta {}\tb {}\tc {}'.format(Nx,Ny,Nz), - 'grid\ta {}\tb {}\tc {}'.format(*geom.grid), + 'grid\ta {}\tb {}\tc {}'.format(*geom.cells), 'size\tx {}\ty {}\tz {}'.format(*geom.size), 'origin\tx {}\ty {}\tz {}'.format(*geom.origin), ] diff --git a/python/damask/__init__.py b/python/damask/__init__.py index a1ccfa3f6..fa1af9f4f 100644 --- a/python/damask/__init__.py +++ b/python/damask/__init__.py @@ -32,7 +32,7 @@ from ._vtk import VTK # noqa from ._colormap import Colormap # noqa from ._config import Config # noqa from ._configmaterial import ConfigMaterial # noqa -from ._geom import Geom # noqa +from ._grid import Grid # noqa from ._result import Result # noqa diff --git a/python/damask/_colormap.py b/python/damask/_colormap.py index aaa3fdc4a..5a22f049b 100644 --- a/python/damask/_colormap.py +++ b/python/damask/_colormap.py @@ -57,7 +57,7 @@ class Colormap(mpl.colors.ListedColormap): ax1.imshow(np.linspace(0,1,self.N).reshape(1,-1), aspect='auto', cmap=self, interpolation='nearest') plt.show(block = False) - return self.name + return 'Colormap: '+self.name @staticmethod @@ -225,7 +225,7 @@ class Colormap(mpl.colors.ListedColormap): def save_paraview(self,fname=None): """ - Write colormap to JSON file for Paraview. + Save as JSON file for use in Paraview. Parameters ---------- @@ -260,7 +260,7 @@ class Colormap(mpl.colors.ListedColormap): def save_ASCII(self,fname=None): """ - Write colormap to ASCII table. + Save as ASCII file. Parameters ---------- @@ -286,7 +286,7 @@ class Colormap(mpl.colors.ListedColormap): def save_GOM(self,fname=None): """ - Write colormap to GOM Aramis compatible format. + Save as ASCII file for use in GOM Aramis. Parameters ---------- @@ -314,7 +314,7 @@ class Colormap(mpl.colors.ListedColormap): def save_gmsh(self,fname=None): """ - Write colormap to Gmsh compatible format. + Save as ASCII file for use in gmsh. Parameters ---------- diff --git a/python/damask/_config.py b/python/damask/_config.py index 24245f4bd..76955588f 100644 --- a/python/damask/_config.py +++ b/python/damask/_config.py @@ -21,6 +21,9 @@ class NiceDumper(yaml.SafeDumper): return self.represent_data(dict(data)) if isinstance(data, dict) and type(data) != dict else \ super().represent_data(data) + def ignore_aliases(self, data): + """No references.""" + return True class Config(dict): """YAML-based configuration.""" diff --git a/python/damask/_configmaterial.py b/python/damask/_configmaterial.py index 6de2283f4..b94e9897a 100644 --- a/python/damask/_configmaterial.py +++ b/python/damask/_configmaterial.py @@ -9,6 +9,16 @@ from . import Orientation class ConfigMaterial(Config): """Material configuration.""" + _defaults = {'material': [], + 'homogenization': {}, + 'phase': {}} + + def __init__(self,d={}): + """Initialize object with default dictionary keys.""" + super().__init__(d) + for k,v in self._defaults.items(): + if k not in self: self[k] = v + def save(self,fname='material.yaml',**kwargs): """ Save to yaml file. @@ -75,6 +85,8 @@ class ConfigMaterial(Config): fraction: 1.0 phase: Steel homogenization: SX + homogenization: {} + phase: {} """ constituents_ = {k:table.get(v) for k,v in constituents.items()} @@ -261,6 +273,8 @@ class ConfigMaterial(Config): fraction: 1.0 phase: Aluminum homogenization: SX + homogenization: {} + phase: {} """ length = -1 @@ -274,6 +288,7 @@ class ConfigMaterial(Config): c = [{} for _ in range(length)] if constituents is None else \ [{'constituents':u} for u in ConfigMaterial._constituents(**constituents)] + if len(c) == 1: c = [copy.deepcopy(c[0]) for _ in range(length)] if length != 1 and length != len(c): diff --git a/python/damask/_geom.py b/python/damask/_grid.py similarity index 74% rename from python/damask/_geom.py rename to python/damask/_grid.py index fece522c3..8380bbc5b 100644 --- a/python/damask/_geom.py +++ b/python/damask/_grid.py @@ -7,7 +7,8 @@ import warnings import numpy as np import pandas as pd import h5py -from scipy import ndimage,spatial +from scipy import ndimage, spatial +from vtk.util.numpy_support import vtk_to_numpy as vtk_to_np from . import environment from . import VTK @@ -16,21 +17,21 @@ from . import grid_filters from . import Rotation -class Geom: +class Grid: """Geometry definition for grid solvers.""" def __init__(self,material,size,origin=[0.0,0.0,0.0],comments=[]): """ - New geometry definition from array of materials, size, and origin. + New grid definition from array of materials, size, and origin. Parameters ---------- material : numpy.ndarray Material index array (3D). size : list or numpy.ndarray - Physical size of the geometry in meter. + Physical size of the grid in meter. origin : list or numpy.ndarray, optional - Physical origin of the geometry in meter. + Physical origin of the grid in meter. comments : list of str, optional Comment lines. @@ -42,23 +43,26 @@ class Geom: def __repr__(self): - """Basic information on geometry definition.""" + """Basic information on grid definition.""" + mat_min = np.nanmin(self.material) + mat_max = np.nanmax(self.material) + mat_N = self.N_materials return util.srepr([ - f'grid a b c: {util.srepr(self.grid, " x ")}', - f'size x y z: {util.srepr(self.size, " x ")}', - f'origin x y z: {util.srepr(self.origin," ")}', - f'# materials: {self.N_materials}', - f'max material: {np.nanmax(self.material)}', + f'cells a b c: {util.srepr(self.cells, " x ")}', + f'size x y z: {util.srepr(self.size, " x ")}', + f'origin x y z: {util.srepr(self.origin," ")}', + f'# materials: {mat_N}' + ('' if mat_min == 0 and mat_max+1 == mat_N else + f' (min: {mat_min}, max: {mat_max})') ]) def __copy__(self): - """Copy geometry.""" + """Copy grid.""" return copy.deepcopy(self) def copy(self): - """Copy geometry.""" + """Copy grid.""" return self.__copy__() @@ -68,14 +72,14 @@ class Geom: Parameters ---------- - other : Geom - Geometry to compare self against. + other : damask.Grid + Grid to compare self against. """ message = [] - if np.any(other.grid != self.grid): - message.append(util.deemph(f'grid a b c: {util.srepr(other.grid," x ")}')) - message.append(util.emph( f'grid a b c: {util.srepr( self.grid," x ")}')) + if np.any(other.cells != self.cells): + message.append(util.deemph(f'cells a b c: {util.srepr(other.cells," x ")}')) + message.append(util.emph( f'cells a b c: {util.srepr( self.cells," x ")}')) if not np.allclose(other.size,self.size): message.append(util.deemph(f'size x y z: {util.srepr(other.size," x ")}')) @@ -104,9 +108,9 @@ class Geom: @material.setter def material(self,material): if len(material.shape) != 3: - raise ValueError(f'Invalid material shape {material.shape}.') + raise ValueError(f'invalid material shape {material.shape}') elif material.dtype not in np.sctypes['float'] + np.sctypes['int']: - raise TypeError(f'Invalid material data type {material.dtype}.') + raise TypeError(f'invalid material data type {material.dtype}') else: self._material = np.copy(material) @@ -117,31 +121,31 @@ class Geom: @property def size(self): - """Physical size of geometry in meter.""" + """Physical size of grid in meter.""" return self._size @size.setter def size(self,size): if len(size) != 3 or any(np.array(size) <= 0): - raise ValueError(f'Invalid size {size}.') + raise ValueError(f'invalid size {size}') else: self._size = np.array(size) @property def origin(self): - """Coordinates of geometry origin in meter.""" + """Coordinates of grid origin in meter.""" return self._origin @origin.setter def origin(self,origin): if len(origin) != 3: - raise ValueError(f'Invalid origin {origin}.') + raise ValueError(f'invalid origin {origin}') else: self._origin = np.array(origin) @property def comments(self): - """Comments/history of geometry.""" + """Comments, e.g. history of operations.""" return self._comments @comments.setter @@ -150,35 +154,39 @@ class Geom: @property - def grid(self): - """Grid dimension of geometry.""" + def cells(self): + """Number of cells in x,y,z direction.""" return np.asarray(self.material.shape) @property def N_materials(self): - """Number of (unique) material indices within geometry.""" + """Number of (unique) material indices within grid.""" return np.unique(self.material).size @staticmethod def load(fname): """ - Read a VTK rectilinear grid. + Load from VTK rectilinear grid file. Parameters ---------- fname : str or or pathlib.Path - Geometry file to read. - Valid extension is .vtr, which will be appended if not given. + Grid file to read. Valid extension is .vtr, which will be appended + if not given. """ v = VTK.load(fname if str(fname).endswith('.vtr') else str(fname)+'.vtr') comments = v.get_comments() - grid = np.array(v.vtk_data.GetDimensions())-1 - bbox = np.array(v.vtk_data.GetBounds()).reshape(3,2).T + cells = np.array(v.vtk_data.GetDimensions())-1 + bbox = np.array(v.vtk_data.GetBounds()).reshape(3,2).T - return Geom(material = v.get('material').reshape(grid,order='F'), + for i,c in enumerate([v.vtk_data.GetXCoordinates(),v.vtk_data.GetYCoordinates(),v.vtk_data.GetZCoordinates()]): + if not np.allclose(vtk_to_np(c),np.linspace(bbox[0][i],bbox[1][i],cells[i]+1)): + raise ValueError('regular grid spacing violated') + + return Grid(material = v.get('material').reshape(cells,order='F'), size = bbox[1] - bbox[0], origin = bbox[0], comments=comments) @@ -187,7 +195,7 @@ class Geom: @staticmethod def load_ASCII(fname): """ - Read a geom file. + Load from geom file. Storing geometry files in ASCII format is deprecated. This function will be removed in a future version of DAMASK. @@ -211,7 +219,7 @@ class Geom: except ValueError: header_length,keyword = (-1, 'invalid') if not keyword.startswith('head') or header_length < 3: - raise TypeError('Header length information missing or invalid') + raise TypeError('header length information missing or invalid') comments = [] content = f.readlines() @@ -219,7 +227,7 @@ class Geom: items = line.split('#')[0].lower().strip().split() key = items[0] if items else '' if key == 'grid': - grid = np.array([ int(dict(zip(items[1::2],items[2::2]))[i]) for i in ['a','b','c']]) + cells = np.array([ int(dict(zip(items[1::2],items[2::2]))[i]) for i in ['a','b','c']]) elif key == 'size': size = np.array([float(dict(zip(items[1::2],items[2::2]))[i]) for i in ['x','y','z']]) elif key == 'origin': @@ -227,7 +235,7 @@ class Geom: else: comments.append(line.strip()) - material = np.empty(grid.prod()) # initialize as flat array + material = np.empty(cells.prod()) # initialize as flat array i = 0 for line in content[header_length:]: items = line.split('#')[0].split() @@ -242,19 +250,19 @@ class Geom: material[i:i+len(items)] = items i += len(items) - if i != grid.prod(): - raise TypeError(f'Invalid file: expected {grid.prod()} entries, found {i}') + if i != cells.prod(): + raise TypeError(f'invalid file: expected {cells.prod()} entries, found {i}') if not np.any(np.mod(material,1) != 0.0): # no float present material = material.astype('int') - (1 if material.min() > 0 else 0) - return Geom(material.reshape(grid,order='F'),size,origin,comments) + return Grid(material.reshape(cells,order='F'),size,origin,comments) @staticmethod def load_DREAM3D(fname,base_group,point_data=None,material='FeatureIds'): """ - Load a DREAM.3D file. + Load from DREAM.3D file. Parameters ---------- @@ -274,21 +282,21 @@ class Geom: root_dir ='DataContainers' f = h5py.File(fname, 'r') g = path.join(root_dir,base_group,'_SIMPL_GEOMETRY') - grid = f[path.join(g,'DIMENSIONS')][()] - size = f[path.join(g,'SPACING')][()] * grid + cells = f[path.join(g,'DIMENSIONS')][()] + size = f[path.join(g,'SPACING')][()] * cells origin = f[path.join(g,'ORIGIN')][()] - ma = np.arange(grid.prod(),dtype=int) \ + ma = np.arange(cells.prod(),dtype=int) \ if point_data is None else \ - np.reshape(f[path.join(root_dir,base_group,point_data,material)],grid.prod()) + np.reshape(f[path.join(root_dir,base_group,point_data,material)],cells.prod()) - return Geom(ma.reshape(grid,order='F'),size,origin,util.execution_stamp('Geom','load_DREAM3D')) + return Grid(ma.reshape(cells,order='F'),size,origin,util.execution_stamp('Grid','load_DREAM3D')) @staticmethod def from_table(table,coordinates,labels): """ - Derive geometry from an ASCII table. + Generate grid from ASCII table. Parameters ---------- @@ -302,15 +310,15 @@ class Geom: Each unique combintation of values results in one material ID. """ - grid,size,origin = grid_filters.cell_coord0_gridSizeOrigin(table.get(coordinates)) + cells,size,origin = grid_filters.cellsSizeOrigin_coordinates0_point(table.get(coordinates)) labels_ = [labels] if isinstance(labels,str) else labels unique,unique_inverse = np.unique(np.hstack([table.get(l) for l in labels_]),return_inverse=True,axis=0) - ma = np.arange(grid.prod()) if len(unique) == grid.prod() else \ + ma = np.arange(cells.prod()) if len(unique) == cells.prod() else \ np.arange(unique.size)[np.argsort(pd.unique(unique_inverse))][unique_inverse] - return Geom(ma.reshape(grid,order='F'),size,origin,util.execution_stamp('Geom','from_table')) + return Grid(ma.reshape(cells,order='F'),size,origin,util.execution_stamp('Grid','from_table')) @staticmethod @@ -318,16 +326,16 @@ class Geom: return np.argmin(np.sum((np.broadcast_to(point,(len(seeds),3))-seeds)**2,axis=1) - weights) @staticmethod - def from_Laguerre_tessellation(grid,size,seeds,weights,material=None,periodic=True): + def from_Laguerre_tessellation(cells,size,seeds,weights,material=None,periodic=True): """ - Generate geometry from Laguerre tessellation. + Generate grid from Laguerre tessellation. Parameters ---------- - grid : int numpy.ndarray of shape (3) - Number of grid points in x,y,z direction. + cells : int numpy.ndarray of shape (3) + Number of cells in x,y,z direction. size : list or numpy.ndarray of shape (3) - Physical size of the geometry in meter. + Physical size of the grid in meter. seeds : numpy.ndarray of shape (:,3) Position of the seed points in meter. All points need to lay within the box. weights : numpy.ndarray of shape (seeds.shape[0]) @@ -336,7 +344,7 @@ class Geom: Material ID of the seeds. Defaults to None, in which case materials are consecutively numbered. periodic : Boolean, optional - Perform a periodic tessellation. Defaults to True. + Assume grid to be periodic. Defaults to True. """ if periodic: @@ -344,57 +352,57 @@ class Geom: seeds_p = np.vstack((seeds -np.array([size[0],0.,0.]),seeds, seeds +np.array([size[0],0.,0.]))) seeds_p = np.vstack((seeds_p-np.array([0.,size[1],0.]),seeds_p,seeds_p+np.array([0.,size[1],0.]))) seeds_p = np.vstack((seeds_p-np.array([0.,0.,size[2]]),seeds_p,seeds_p+np.array([0.,0.,size[2]]))) - coords = grid_filters.cell_coord0(grid*3,size*3,-size).reshape(-1,3) + coords = grid_filters.coordinates0_point(cells*3,size*3,-size).reshape(-1,3) else: weights_p = weights seeds_p = seeds - coords = grid_filters.cell_coord0(grid,size).reshape(-1,3) + coords = grid_filters.coordinates0_point(cells,size).reshape(-1,3) pool = mp.Pool(processes = int(environment.options['DAMASK_NUM_THREADS'])) - result = pool.map_async(partial(Geom._find_closest_seed,seeds_p,weights_p), [coord for coord in coords]) + result = pool.map_async(partial(Grid._find_closest_seed,seeds_p,weights_p), [coord for coord in coords]) pool.close() pool.join() material_ = np.array(result.get()) if periodic: - material_ = material_.reshape(grid*3) - material_ = material_[grid[0]:grid[0]*2,grid[1]:grid[1]*2,grid[2]:grid[2]*2]%seeds.shape[0] + material_ = material_.reshape(cells*3) + material_ = material_[cells[0]:cells[0]*2,cells[1]:cells[1]*2,cells[2]:cells[2]*2]%seeds.shape[0] else: - material_ = material_.reshape(grid) + material_ = material_.reshape(cells) - return Geom(material = material_ if material is None else material[material_], + return Grid(material = material_ if material is None else material[material_], size = size, - comments = util.execution_stamp('Geom','from_Laguerre_tessellation'), + comments = util.execution_stamp('Grid','from_Laguerre_tessellation'), ) @staticmethod - def from_Voronoi_tessellation(grid,size,seeds,material=None,periodic=True): + def from_Voronoi_tessellation(cells,size,seeds,material=None,periodic=True): """ - Generate geometry from Voronoi tessellation. + Generate grid from Voronoi tessellation. Parameters ---------- - grid : int numpy.ndarray of shape (3) - Number of grid points in x,y,z direction. + cells : int numpy.ndarray of shape (3) + Number of cells in x,y,z direction. size : list or numpy.ndarray of shape (3) - Physical size of the geometry in meter. + Physical size of the grid in meter. seeds : numpy.ndarray of shape (:,3) Position of the seed points in meter. All points need to lay within the box. material : numpy.ndarray of shape (seeds.shape[0]), optional Material ID of the seeds. Defaults to None, in which case materials are consecutively numbered. periodic : Boolean, optional - Perform a periodic tessellation. Defaults to True. + Assume grid to be periodic. Defaults to True. """ - coords = grid_filters.cell_coord0(grid,size).reshape(-1,3) + coords = grid_filters.coordinates0_point(cells,size).reshape(-1,3) KDTree = spatial.cKDTree(seeds,boxsize=size) if periodic else spatial.cKDTree(seeds) devNull,material_ = KDTree.query(coords) - return Geom(material = (material_ if material is None else material[material_]).reshape(grid), + return Grid(material = (material_ if material is None else material[material_]).reshape(cells), size = size, - comments = util.execution_stamp('Geom','from_Voronoi_tessellation'), + comments = util.execution_stamp('Grid','from_Voronoi_tessellation'), ) @@ -441,16 +449,16 @@ class Geom: @staticmethod - def from_minimal_surface(grid,size,surface,threshold=0.0,periods=1,materials=(0,1)): + def from_minimal_surface(cells,size,surface,threshold=0.0,periods=1,materials=(0,1)): """ - Generate geometry from definition of triply periodic minimal surface. + Generate grid from definition of triply periodic minimal surface. Parameters ---------- - grid : int numpy.ndarray of shape (3) - Number of grid points in x,y,z direction. + cells : int numpy.ndarray of shape (3) + Number of cells in x,y,z direction. size : list or numpy.ndarray of shape (3) - Physical size of the geometry in meter. + Physical size of the grid in meter. surface : str Type of the minimal surface. See notes for details. threshold : float, optional. @@ -493,19 +501,19 @@ class Geom: https://doi.org/10.1016/j.simpa.2020.100026 """ - x,y,z = np.meshgrid(periods*2.0*np.pi*(np.arange(grid[0])+0.5)/grid[0], - periods*2.0*np.pi*(np.arange(grid[1])+0.5)/grid[1], - periods*2.0*np.pi*(np.arange(grid[2])+0.5)/grid[2], + x,y,z = np.meshgrid(periods*2.0*np.pi*(np.arange(cells[0])+0.5)/cells[0], + periods*2.0*np.pi*(np.arange(cells[1])+0.5)/cells[1], + periods*2.0*np.pi*(np.arange(cells[2])+0.5)/cells[2], indexing='ij',sparse=True) - return Geom(material = np.where(threshold < Geom._minimal_surface[surface](x,y,z),materials[1],materials[0]), + return Grid(material = np.where(threshold < Grid._minimal_surface[surface](x,y,z),materials[1],materials[0]), size = size, - comments = util.execution_stamp('Geom','from_minimal_surface'), + comments = util.execution_stamp('Grid','from_minimal_surface'), ) def save(self,fname,compress=True): """ - Store as VTK rectilinear grid. + Save as VTK rectilinear grid file. Parameters ---------- @@ -515,7 +523,7 @@ class Geom: Compress with zlib algorithm. Defaults to True. """ - v = VTK.from_rectilinear_grid(self.grid,self.size,self.origin) + v = VTK.from_rectilinear_grid(self.cells,self.size,self.origin) v.add(self.material.flatten(order='F'),'material') v.add_comments(self.comments) @@ -524,7 +532,7 @@ class Geom: def save_ASCII(self,fname): """ - Write a geom file. + Save as geom file. Storing geometry files in ASCII format is deprecated. This function will be removed in a future version of DAMASK. @@ -539,7 +547,7 @@ class Geom: """ warnings.warn('Support for ASCII-based geom format will be removed in DAMASK 3.1.0', DeprecationWarning) header = [f'{len(self.comments)+4} header'] + self.comments \ - + ['grid a {} b {} c {}'.format(*self.grid), + + ['grid a {} b {} c {}'.format(*self.cells), 'size x {} y {} z {}'.format(*self.size), 'origin x {} y {} z {}'.format(*self.origin), 'homogenization 1', @@ -548,13 +556,13 @@ class Geom: format_string = '%g' if self.material.dtype in np.sctypes['float'] else \ '%{}i'.format(1+int(np.floor(np.log10(np.nanmax(self.material))))) np.savetxt(fname, - self.material.reshape([self.grid[0],np.prod(self.grid[1:])],order='F').T, + self.material.reshape([self.cells[0],np.prod(self.cells[1:])],order='F').T, header='\n'.join(header), fmt=format_string, comments='') def show(self): """Show on screen.""" - VTK.from_rectilinear_grid(self.grid,self.size,self.origin).show() + VTK.from_rectilinear_grid(self.cells,self.size,self.origin).show() def add_primitive(self,dimension,center,exponent, @@ -566,11 +574,10 @@ class Geom: ---------- dimension : int or float numpy.ndarray of shape (3) Dimension (diameter/side length) of the primitive. If given as - integers, grid point locations (cell centers) are addressed. + integers, cell centers are addressed. If given as floats, coordinates are addressed. center : int or float numpy.ndarray of shape (3) - Center of the primitive. If given as integers, grid point - coordinates (cell centers) are addressed. + Center of the primitive. If given as integers, cell centers are addressed. If given as floats, coordinates in space are addressed. exponent : numpy.ndarray of shape (3) or float Exponents for the three axes. @@ -584,44 +591,44 @@ class Geom: Retain original materials within primitive and fill outside. Defaults to False. periodic : Boolean, optional - Repeat primitive over boundaries. Defaults to True. + Assume grid to be periodic. Defaults to True. """ # radius and center - r = np.array(dimension)/2.0*self.size/self.grid if np.array(dimension).dtype in np.sctypes['int'] else \ + r = np.array(dimension)/2.0*self.size/self.cells if np.array(dimension).dtype in np.sctypes['int'] else \ np.array(dimension)/2.0 - c = (np.array(center) + .5)*self.size/self.grid if np.array(center).dtype in np.sctypes['int'] else \ + c = (np.array(center) + .5)*self.size/self.cells if np.array(center).dtype in np.sctypes['int'] else \ (np.array(center) - self.origin) - coords = grid_filters.cell_coord0(self.grid,self.size, - -(0.5*(self.size + (self.size/self.grid + coords = grid_filters.coordinates0_point(self.cells,self.size, + -(0.5*(self.size + (self.size/self.cells if np.array(center).dtype in np.sctypes['int'] else 0)) if periodic else c)) - coords_rot = R.broadcast_to(tuple(self.grid))@coords + coords_rot = R.broadcast_to(tuple(self.cells))@coords with np.errstate(all='ignore'): mask = np.sum(np.power(coords_rot/r,2.0**np.array(exponent)),axis=-1) > 1.0 if periodic: # translate back to center - mask = np.roll(mask,((c/self.size-0.5)*self.grid).round().astype(int),(0,1,2)) + mask = np.roll(mask,((c/self.size-0.5)*self.cells).round().astype(int),(0,1,2)) - return Geom(material = np.where(np.logical_not(mask) if inverse else mask, + return Grid(material = np.where(np.logical_not(mask) if inverse else mask, self.material, np.nanmax(self.material)+1 if fill is None else fill), size = self.size, origin = self.origin, - comments = self.comments+[util.execution_stamp('Geom','add_primitive')], + comments = self.comments+[util.execution_stamp('Grid','add_primitive')], ) def mirror(self,directions,reflect=False): """ - Mirror geometry along given directions. + Mirror grid along given directions. Parameters ---------- directions : iterable containing str - Direction(s) along which the geometry is mirrored. + Direction(s) along which the grid is mirrored. Valid entries are 'x', 'y', 'z'. reflect : bool, optional Reflect (include) outermost layers. Defaults to False. @@ -629,7 +636,7 @@ class Geom: """ valid = ['x','y','z'] if not set(directions).issubset(valid): - raise ValueError(f'Invalid direction {set(directions).difference(valid)} specified.') + raise ValueError(f'invalid direction {set(directions).difference(valid)} specified') limits = [None,None] if reflect else [-2,0] mat = self.material.copy() @@ -641,52 +648,52 @@ class Geom: if 'z' in directions: mat = np.concatenate([mat,mat[:,:,limits[0]:limits[1]:-1]],2) - return Geom(material = mat, - size = self.size/self.grid*np.asarray(mat.shape), + return Grid(material = mat, + size = self.size/self.cells*np.asarray(mat.shape), origin = self.origin, - comments = self.comments+[util.execution_stamp('Geom','mirror')], + comments = self.comments+[util.execution_stamp('Grid','mirror')], ) def flip(self,directions): """ - Flip geometry along given directions. + Flip grid along given directions. Parameters ---------- directions : iterable containing str - Direction(s) along which the geometry is flipped. + Direction(s) along which the grid is flipped. Valid entries are 'x', 'y', 'z'. """ valid = ['x','y','z'] if not set(directions).issubset(valid): - 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)) - return Geom(material = mat, + return Grid(material = mat, size = self.size, origin = self.origin, - comments = self.comments+[util.execution_stamp('Geom','flip')], + comments = self.comments+[util.execution_stamp('Grid','flip')], ) - def scale(self,grid,periodic=True): + def scale(self,cells,periodic=True): """ - Scale geometry to new grid. + Scale grid to new cells. Parameters ---------- - grid : numpy.ndarray of shape (3) - Number of grid points in x,y,z direction. + cells : numpy.ndarray of shape (3) + Number of cells in x,y,z direction. periodic : Boolean, optional - Assume geometry to be periodic. Defaults to True. + Assume grid to be periodic. Defaults to True. """ - return Geom(material = ndimage.interpolation.zoom( + return Grid(material = ndimage.interpolation.zoom( self.material, - grid/self.grid, + cells/self.cells, output=self.material.dtype, order=0, mode=('wrap' if periodic else 'nearest'), @@ -694,13 +701,13 @@ class Geom: ), size = self.size, origin = self.origin, - comments = self.comments+[util.execution_stamp('Geom','scale')], + comments = self.comments+[util.execution_stamp('Grid','scale')], ) def clean(self,stencil=3,selection=None,periodic=True): """ - Smooth geometry by selecting most frequent material index within given stencil at each location. + Smooth grid by selecting most frequent material index within given stencil at each location. Parameters ---------- @@ -709,7 +716,7 @@ class Geom: selection : list, optional Field values that can be altered. Defaults to all. periodic : Boolean, optional - Assume geometry to be periodic. Defaults to True. + Assume grid to be periodic. Defaults to True. """ def mostFrequent(arr,selection=None): @@ -720,7 +727,7 @@ class Geom: else: return me - return Geom(material = ndimage.filters.generic_filter( + return Grid(material = ndimage.filters.generic_filter( self.material, mostFrequent, size=(stencil if selection is None else stencil//2*2+1,)*3, @@ -729,7 +736,7 @@ class Geom: ).astype(self.material.dtype), size = self.size, origin = self.origin, - comments = self.comments+[util.execution_stamp('Geom','clean')], + comments = self.comments+[util.execution_stamp('Grid','clean')], ) @@ -737,21 +744,21 @@ class Geom: """Renumber sorted material indices as 0,...,N-1.""" _,renumbered = np.unique(self.material,return_inverse=True) - return Geom(material = renumbered.reshape(self.grid), + return Grid(material = renumbered.reshape(self.cells), size = self.size, origin = self.origin, - comments = self.comments+[util.execution_stamp('Geom','renumber')], + comments = self.comments+[util.execution_stamp('Grid','renumber')], ) def rotate(self,R,fill=None): """ - Rotate geometry (pad if required). + Rotate grid (pad if required). Parameters ---------- R : damask.Rotation - Rotation to apply to the geometry. + Rotation to apply to the grid. fill : int or float, optional Material index to fill the corners. Defaults to material.max() + 1. @@ -773,25 +780,25 @@ class Geom: else: material_in = material_out - origin = self.origin-(np.asarray(material_in.shape)-self.grid)*.5 * self.size/self.grid + origin = self.origin-(np.asarray(material_in.shape)-self.cells)*.5 * self.size/self.cells - return Geom(material = material_in, - size = self.size/self.grid*np.asarray(material_in.shape), + return Grid(material = material_in, + size = self.size/self.cells*np.asarray(material_in.shape), origin = origin, - comments = self.comments+[util.execution_stamp('Geom','rotate')], + comments = self.comments+[util.execution_stamp('Grid','rotate')], ) - def canvas(self,grid=None,offset=None,fill=None): + def canvas(self,cells=None,offset=None,fill=None): """ - Crop or enlarge/pad geometry. + Crop or enlarge/pad grid. Parameters ---------- - grid : numpy.ndarray of shape (3) - Number of grid points in x,y,z direction. + cells : numpy.ndarray of shape (3) + Number of cells x,y,z direction. offset : numpy.ndarray of shape (3) - Offset (measured in grid points) from old to new geometry [0,0,0]. + Offset (measured in cells) from old to new grid [0,0,0]. fill : int or float, optional Material index to fill the background. Defaults to material.max() + 1. @@ -800,19 +807,19 @@ class Geom: if fill is None: fill = np.nanmax(self.material) + 1 dtype = float if int(fill) != fill or self.material.dtype in np.sctypes['float'] else int - canvas = np.full(self.grid if grid is None else grid,fill,dtype) + canvas = np.full(self.cells if cells is None else cells,fill,dtype) - LL = np.clip( offset, 0,np.minimum(self.grid, grid+offset)) - UR = np.clip( offset+grid, 0,np.minimum(self.grid, grid+offset)) - ll = np.clip(-offset, 0,np.minimum( grid,self.grid-offset)) - ur = np.clip(-offset+self.grid,0,np.minimum( grid,self.grid-offset)) + LL = np.clip( offset, 0,np.minimum(self.cells, cells+offset)) + UR = np.clip( offset+cells, 0,np.minimum(self.cells, cells+offset)) + ll = np.clip(-offset, 0,np.minimum( cells,self.cells-offset)) + ur = np.clip(-offset+self.cells,0,np.minimum( cells,self.cells-offset)) canvas[ll[0]:ur[0],ll[1]:ur[1],ll[2]:ur[2]] = self.material[LL[0]:UR[0],LL[1]:UR[1],LL[2]:UR[2]] - return Geom(material = canvas, - size = self.size/self.grid*np.asarray(canvas.shape), - origin = self.origin+offset*self.size/self.grid, - comments = self.comments+[util.execution_stamp('Geom','canvas')], + return Grid(material = canvas, + size = self.size/self.cells*np.asarray(canvas.shape), + origin = self.origin+offset*self.size/self.cells, + comments = self.comments+[util.execution_stamp('Grid','canvas')], ) @@ -834,10 +841,10 @@ class Geom: mp = np.vectorize(mp) mapper = dict(zip(from_material,to_material)) - return Geom(material = mp(self.material,mapper).reshape(self.grid), + return Grid(material = mp(self.material,mapper).reshape(self.cells), size = self.size, origin = self.origin, - comments = self.comments+[util.execution_stamp('Geom','substitute')], + comments = self.comments+[util.execution_stamp('Grid','substitute')], ) @@ -848,10 +855,10 @@ class Geom: sort_idx = np.argsort(from_ma) ma = np.unique(a)[sort_idx][np.searchsorted(from_ma,a,sorter = sort_idx)] - return Geom(material = ma.reshape(self.grid,order='F'), + return Grid(material = ma.reshape(self.cells,order='F'), size = self.size, origin = self.origin, - comments = self.comments+[util.execution_stamp('Geom','sort')], + comments = self.comments+[util.execution_stamp('Grid','sort')], ) @@ -861,7 +868,7 @@ class Geom: Different from themselves (or listed as triggers) within a given (cubic) vicinity, i.e. within the region close to a grain/phase boundary. - ToDo: use include/exclude as in seeds.from_geom + ToDo: use include/exclude as in seeds.from_grid Parameters ---------- @@ -875,7 +882,7 @@ class Geom: List of material indices that trigger a change. Defaults to [], meaning that any different neighbor triggers a change. periodic : Boolean, optional - Assume geometry to be periodic. Defaults to True. + Assume grid to be periodic. Defaults to True. """ def tainted_neighborhood(stencil,trigger): @@ -892,10 +899,10 @@ class Geom: mode='wrap' if periodic else 'nearest', extra_keywords={'trigger':trigger}) - return Geom(material = np.where(mask, self.material + offset_,self.material), + return Grid(material = np.where(mask, self.material + offset_,self.material), size = self.size, origin = self.origin, - comments = self.comments+[util.execution_stamp('Geom','vicinity_offset')], + comments = self.comments+[util.execution_stamp('Grid','vicinity_offset')], ) @@ -905,20 +912,20 @@ class Geom: Parameters ---------- - periodic : bool, optional - Show boundaries across periodicity. Defaults to True. + periodic : Boolean, optional + Assume grid to be periodic. Defaults to True. directions : iterable containing str, optional - Direction(s) along which the geometry is mirrored. + Direction(s) along which the boundaries are determined. Valid entries are 'x', 'y', 'z'. Defaults to 'xyz'. """ valid = ['x','y','z'] if not set(directions).issubset(valid): - raise ValueError(f'Invalid direction {set(directions).difference(valid)} specified.') + raise ValueError(f'invalid direction {set(directions).difference(valid)} specified') - o = [[0, self.grid[0]+1, np.prod(self.grid[:2]+1)+self.grid[0]+1, np.prod(self.grid[:2]+1)], - [0, np.prod(self.grid[:2]+1), np.prod(self.grid[:2]+1)+1, 1], - [0, 1, self.grid[0]+1+1, self.grid[0]+1]] # offset for connectivity + o = [[0, self.cells[0]+1, np.prod(self.cells[:2]+1)+self.cells[0]+1, np.prod(self.cells[:2]+1)], + [0, np.prod(self.cells[:2]+1), np.prod(self.cells[:2]+1)+1, 1], + [0, 1, self.cells[0]+1+1, self.cells[0]+1]] # offset for connectivity connectivity = [] for i,d in enumerate(['x','y','z']): @@ -933,5 +940,5 @@ class Geom: base_nodes = np.argwhere(mask.flatten(order='F')).reshape(-1,1) connectivity.append(np.block([base_nodes + o[i][k] for k in range(4)])) - coords = grid_filters.node_coord0(self.grid,self.size,self.origin).reshape(-1,3,order='F') + coords = grid_filters.coordinates0_node(self.cells,self.size,self.origin).reshape(-1,3,order='F') return VTK.from_unstructured_grid(coords,np.vstack(connectivity),'QUAD') diff --git a/python/damask/_orientation.py b/python/damask/_orientation.py index 05301561f..e6434813e 100644 --- a/python/damask/_orientation.py +++ b/python/damask/_orientation.py @@ -226,9 +226,9 @@ class Orientation(Rotation): """ return super().__eq__(other) \ - and self.family == other.family \ - and self.lattice == other.lattice \ - and self.parameters == other.parameters + and hasattr(other, 'family') and self.family == other.family \ + and hasattr(other, 'lattice') and self.lattice == other.lattice \ + and hasattr(other, 'parameters') and self.parameters == other.parameters def __matmul__(self,other): diff --git a/python/damask/_result.py b/python/damask/_result.py index 0e74f86df..5e37042e0 100644 --- a/python/damask/_result.py +++ b/python/damask/_result.py @@ -46,13 +46,17 @@ class Result: self.version_major = f.attrs['DADF5_version_major'] self.version_minor = f.attrs['DADF5_version_minor'] - if self.version_major != 0 or not 7 <= self.version_minor <= 9: + if self.version_major != 0 or not 7 <= self.version_minor <= 11: raise TypeError(f'Unsupported DADF5 version {self.version_major}.{self.version_minor}') - self.structured = 'grid' in f['geometry'].attrs.keys() + self.structured = 'grid' in f['geometry'].attrs.keys() or \ + 'cells' in f['geometry'].attrs.keys() if self.structured: - self.grid = f['geometry'].attrs['grid'] + try: + self.cells = f['geometry'].attrs['cells'] + except KeyError: + self.cells = f['geometry'].attrs['grid'] self.size = f['geometry'].attrs['size'] self.origin = f['geometry'].attrs['origin'] @@ -558,19 +562,19 @@ class Result: return dataset @property - def cell_coordinates(self): + def coordinates0_point(self): """Return initial coordinates of the cell centers.""" if self.structured: - return grid_filters.cell_coord0(self.grid,self.size,self.origin).reshape(-1,3,order='F') + return grid_filters.coordinates0_point(self.cells,self.size,self.origin).reshape(-1,3,order='F') else: with h5py.File(self.fname,'r') as f: return f['geometry/x_c'][()] @property - def node_coordinates(self): + def coordinates0_node(self): """Return initial coordinates of the cell centers.""" if self.structured: - return grid_filters.node_coord0(self.grid,self.size,self.origin).reshape(-1,3,order='F') + return grid_filters.coordinates0_node(self.cells,self.size,self.origin).reshape(-1,3,order='F') else: with h5py.File(self.fname,'r') as f: return f['geometry/x_n'][()] @@ -780,13 +784,16 @@ class Result: @staticmethod - def _add_IPF_color(q,l): + def _add_IPF_color(l,q): m = util.scale_to_coprime(np.array(l)) try: lattice = {'fcc':'cF','bcc':'cI','hex':'hP'}[q['meta']['Lattice']] except KeyError: lattice = q['meta']['Lattice'] - o = Orientation(rotation = (rfn.structured_to_unstructured(q['data'])),lattice=lattice) + try: + o = Orientation(rotation = (rfn.structured_to_unstructured(q['data'])),lattice=lattice) + except ValueError: + o = Orientation(rotation = q['data'],lattice=lattice) return { 'data': np.uint8(o.IPF_color(l)*255), @@ -798,16 +805,17 @@ class Result: 'Creator': 'add_IPF_color' } } - def add_IPF_color(self,q,l): + def add_IPF_color(self,l,q='O'): """ Add RGB color tuple of inverse pole figure (IPF) color. Parameters ---------- - q : str - Label of the dataset containing the crystallographic orientation as quaternions. l : numpy.array of shape (3) Lab frame direction for inverse pole figure. + q : str + Label of the dataset containing the crystallographic orientation as quaternions. + Defaults to 'O'. """ self._add_generic_pointwise(self._add_IPF_color,{'q':q},{'l':l}) @@ -1125,6 +1133,7 @@ class Result: Arguments parsed to func. """ + chunk_size = 1024**2//8 num_threads = damask.environment.options['DAMASK_NUM_THREADS'] pool = mp.Pool(int(num_threads) if num_threads is not None else None) lock = mp.Manager().Lock() @@ -1148,7 +1157,15 @@ class Result: dataset.attrs['Overwritten'] = 'Yes' if h5py3 else \ 'Yes'.encode() else: - dataset = f[result[0]].create_dataset(result[1]['label'],data=result[1]['data']) + if result[1]['data'].size >= chunk_size*2: + shape = result[1]['data'].shape + chunks = (chunk_size//np.prod(shape[1:]),)+shape[1:] + dataset = f[result[0]].create_dataset(result[1]['label'],data=result[1]['data'], + maxshape=shape, chunks=chunks, + compression='gzip', compression_opts=6, + shuffle=True,fletcher32=True) + else: + dataset = f[result[0]].create_dataset(result[1]['label'],data=result[1]['data']) now = datetime.datetime.now().astimezone() dataset.attrs['Created'] = now.strftime('%Y-%m-%d %H:%M:%S%z') if h5py3 else \ @@ -1218,7 +1235,7 @@ class Result: topology=ET.SubElement(grid, 'Topology') topology.attrib={'TopologyType': '3DCoRectMesh', - 'Dimensions': '{} {} {}'.format(*self.grid+1)} + 'Dimensions': '{} {} {}'.format(*self.cells+1)} geometry=ET.SubElement(grid, 'Geometry') geometry.attrib={'GeometryType':'Origin_DxDyDz'} @@ -1233,7 +1250,7 @@ class Result: delta.attrib={'Format': 'XML', 'NumberType': 'Float', 'Dimensions': '3'} - delta.text="{} {} {}".format(*(self.size/self.grid)) + delta.text="{} {} {}".format(*(self.size/self.cells)) with h5py.File(self.fname,'r') as f: @@ -1244,7 +1261,7 @@ class Result: data_items.append(ET.SubElement(attributes[-1], 'DataItem')) data_items[-1].attrib={'Format': 'HDF', 'Precision': '8', - 'Dimensions': '{} {} {} 3'.format(*(self.grid+1))} + 'Dimensions': '{} {} {} 3'.format(*(self.cells+1))} data_items[-1].text=f'{os.path.split(self.fname)[1]}:/{inc}/geometry/u_n' for o,p in zip(['phases','homogenizations'],['out_type_ph','out_type_ho']): @@ -1267,8 +1284,8 @@ class Result: data_items[-1].attrib={'Format': 'HDF', 'NumberType': number_type_map(dtype), 'Precision': f'{dtype.itemsize}', - 'Dimensions': '{} {} {} {}'.format(*self.grid,1 if shape == () else - np.prod(shape))} + 'Dimensions': '{} {} {} {}'.format(*self.cells,1 if shape == () else + np.prod(shape))} data_items[-1].text=f'{os.path.split(self.fname)[1]}:{name}' with open(self.fname.with_suffix('.xdmf').name,'w') as f: @@ -1291,7 +1308,7 @@ class Result: if mode.lower()=='cell': if self.structured: - v = VTK.from_rectilinear_grid(self.grid,self.size,self.origin) + v = VTK.from_rectilinear_grid(self.cells,self.size,self.origin) else: with h5py.File(self.fname,'r') as f: v = VTK.from_unstructured_grid(f['/geometry/x_n'][()], @@ -1299,7 +1316,7 @@ class Result: f['/geometry/T_c'].attrs['VTK_TYPE'] if h5py3 else \ f['/geometry/T_c'].attrs['VTK_TYPE'].decode()) elif mode.lower()=='point': - v = VTK.from_poly_data(self.cell_coordinates) + v = VTK.from_poly_data(self.coordinates0_point) N_digits = int(np.floor(np.log10(max(1,int(self.increments[-1][3:])))))+1 diff --git a/python/damask/_rotation.py b/python/damask/_rotation.py index 5fb8109c3..78029b59a 100644 --- a/python/damask/_rotation.py +++ b/python/damask/_rotation.py @@ -144,6 +144,11 @@ class Rotation: return self.copy(rotation=Rotation(np.block([np.cos(pwr*phi),np.sin(pwr*phi)*p]))._standardize()) + def __mul__(self,other): + """Standard multiplication is not implemented.""" + raise NotImplementedError('Use "R@b", i.e. matmul, to apply rotation "R" to object "b"') + + def __matmul__(self,other): """ Rotation of vector, second or fourth order tensor, or rotation object. @@ -199,8 +204,16 @@ class Rotation: def append(self,other): - """Extend rotation array along first dimension with other array.""" - return self.copy(rotation=np.vstack((self.quaternion,other.quaternion))) + """ + Extend rotation array along first dimension with other array(s). + + Parameters + ---------- + other : Rotation or list of Rotations. + + """ + return self.copy(rotation=np.vstack(tuple(map(lambda x:x.quaternion, + [self]+other if isinstance(other,list) else [self,other])))) def flatten(self,order = 'C'): @@ -258,7 +271,7 @@ class Rotation: """Intermediate representation supporting quaternion averaging.""" return np.einsum('...i,...j',quat,quat) - if not weights: + if weights is None: weights = np.ones(self.shape,dtype=float) eig, vec = np.linalg.eig(np.sum(_M(self.quaternion) * weights[...,np.newaxis,np.newaxis],axis=-3) \ @@ -763,7 +776,7 @@ class Rotation: def _dg(eu,deg): """Return infinitesimal Euler space volume of bin(s).""" phi_sorted = eu[np.lexsort((eu[:,0],eu[:,1],eu[:,2]))] - steps,size,_ = grid_filters.cell_coord0_gridSizeOrigin(phi_sorted) + steps,size,_ = grid_filters.cellsSizeOrigin_coordinates0_point(phi_sorted) delta = np.radians(size/steps) if deg else size/steps return delta[0]*2.0*np.sin(delta[1]/2.0)*delta[2] / 8.0 / np.pi**2 * np.sin(np.radians(eu[:,1]) if deg else eu[:,1]) diff --git a/python/damask/_table.py b/python/damask/_table.py index c05fa71a7..e6e6c4eeb 100644 --- a/python/damask/_table.py +++ b/python/damask/_table.py @@ -33,6 +33,10 @@ class Table: """Brief overview.""" return '\n'.join(['# '+c for c in self.comments])+'\n'+self.data.__repr__() + def __getitem__(self,item): + """Return slice according to item.""" + return self.__class__(data=self.data[item],shapes=self.shapes,comments=self.comments) + def __len__(self): """Number of rows.""" return len(self.data) @@ -73,7 +77,7 @@ class Table: @staticmethod def load(fname): """ - Load ASCII table file. + Load from ASCII table file. In legacy style, the first line indicates the number of subsequent header lines as "N header", with the last header line being @@ -131,7 +135,7 @@ class Table: @staticmethod def load_ang(fname): """ - Load ang file. + Load from ang file. A valid TSL ang file needs to contains the following columns: * Euler angles (Bunge notation) in radians, 3 floats, label 'eu'. diff --git a/python/damask/_vtk.py b/python/damask/_vtk.py index 2f4d63791..224412f7c 100644 --- a/python/damask/_vtk.py +++ b/python/damask/_vtk.py @@ -76,7 +76,8 @@ class VTK: nodes : numpy.ndarray of shape (:,3) Spatial position of the nodes. connectivity : numpy.ndarray of np.dtype = int - Cell connectivity (0-based), first dimension determines #Cells, second dimension determines #Nodes/Cell. + Cell connectivity (0-based), first dimension determines #Cells, + second dimension determines #Nodes/Cell. cell_type : str Name of the vtk.vtkCell subclass. Tested for TRIANGLE, QUAD, TETRA, and HEXAHEDRON. @@ -91,7 +92,9 @@ class VTK: vtk_data = vtk.vtkUnstructuredGrid() vtk_data.SetPoints(vtk_nodes) - vtk_data.SetCells(eval(f'vtk.VTK_{cell_type.split("_",1)[-1].upper()}'),cells) + cell_types = {'TRIANGLE':vtk.VTK_TRIANGLE, 'QUAD':vtk.VTK_QUAD, + 'TETRA' :vtk.VTK_TETRA, 'HEXAHEDRON':vtk.VTK_HEXAHEDRON} + vtk_data.SetCells(cell_types[cell_type.split("_",1)[-1].upper()],cells) return VTK(vtk_data) @@ -128,7 +131,7 @@ class VTK: @staticmethod def load(fname,dataset_type=None): """ - Create VTK from file. + Load from VTK file. Parameters ---------- @@ -181,7 +184,7 @@ class VTK: writer.Write() def save(self,fname,parallel=True,compress=True): """ - Write to file. + Save as VTK file. Parameters ---------- diff --git a/python/damask/grid_filters.py b/python/damask/grid_filters.py index 6c3f24cff..ee929b3bf 100644 --- a/python/damask/grid_filters.py +++ b/python/damask/grid_filters.py @@ -4,38 +4,38 @@ Filters for operations on regular grids. Notes ----- The grids are defined as (x,y,z,...) where x is fastest and z is slowest. -This convention is consistent with the geom file format. +This convention is consistent with the layout in grid vtr files. When converting to/from a plain list (e.g. storage in ASCII table), the following operations are required for tensorial data: -D3 = D1.reshape(grid+(-1,),order='F').reshape(grid+(3,3)) -D1 = D3.reshape(grid+(-1,)).reshape(-1,9,order='F') +D3 = D1.reshape(cells+(-1,),order='F').reshape(cells+(3,3)) +D1 = D3.reshape(cells+(-1,)).reshape(-1,9,order='F') """ from scipy import spatial as _spatial import numpy as _np -def _ks(size,grid,first_order=False): +def _ks(size,cells,first_order=False): """ Get wave numbers operator. Parameters ---------- size : numpy.ndarray of shape (3) - physical size of the periodic field. - grid : numpy.ndarray of shape (3) - number of grid points. + Physical size of the periodic field. + cells : numpy.ndarray of shape (3) + Number of cells. first_order : bool, optional - correction for first order derivatives, defaults to False. + Correction for first order derivatives, defaults to False. """ - k_sk = _np.where(_np.arange(grid[0])>grid[0]//2,_np.arange(grid[0])-grid[0],_np.arange(grid[0]))/size[0] - if grid[0]%2 == 0 and first_order: k_sk[grid[0]//2] = 0 # Nyquist freq=0 for even grid (Johnson, MIT, 2011) + k_sk = _np.where(_np.arange(cells[0])>cells[0]//2,_np.arange(cells[0])-cells[0],_np.arange(cells[0]))/size[0] + if cells[0]%2 == 0 and first_order: k_sk[cells[0]//2] = 0 # Nyquist freq=0 for even cells (Johnson, MIT, 2011) - k_sj = _np.where(_np.arange(grid[1])>grid[1]//2,_np.arange(grid[1])-grid[1],_np.arange(grid[1]))/size[1] - if grid[1]%2 == 0 and first_order: k_sj[grid[1]//2] = 0 # Nyquist freq=0 for even grid (Johnson, MIT, 2011) + k_sj = _np.where(_np.arange(cells[1])>cells[1]//2,_np.arange(cells[1])-cells[1],_np.arange(cells[1]))/size[1] + if cells[1]%2 == 0 and first_order: k_sj[cells[1]//2] = 0 # Nyquist freq=0 for even cells (Johnson, MIT, 2011) - k_si = _np.arange(grid[2]//2+1)/size[2] + k_si = _np.arange(cells[2]//2+1)/size[2] return _np.stack(_np.meshgrid(k_sk,k_sj,k_si,indexing = 'ij'), axis=-1) @@ -47,9 +47,9 @@ def curl(size,field): Parameters ---------- size : numpy.ndarray of shape (3) - physical size of the periodic field. + Physical size of the periodic field. field : numpy.ndarray of shape (:,:,:,3) or (:,:,:,3,3) - periodic field of which the curl is calculated. + Periodic field of which the curl is calculated. """ n = _np.prod(field.shape[3:]) @@ -73,9 +73,9 @@ def divergence(size,field): Parameters ---------- size : numpy.ndarray of shape (3) - physical size of the periodic field. + Physical size of the periodic field. field : numpy.ndarray of shape (:,:,:,3) or (:,:,:,3,3) - periodic field of which the divergence is calculated. + Periodic field of which the divergence is calculated. """ n = _np.prod(field.shape[3:]) @@ -95,9 +95,9 @@ def gradient(size,field): Parameters ---------- size : numpy.ndarray of shape (3) - physical size of the periodic field. + Physical size of the periodic field. field : numpy.ndarray of shape (:,:,:,1) or (:,:,:,3) - periodic field of which the gradient is calculated. + Periodic field of which the gradient is calculated. """ n = _np.prod(field.shape[3:]) @@ -110,39 +110,39 @@ def gradient(size,field): return _np.fft.irfftn(grad_,axes=(0,1,2),s=field.shape[:3]) -def cell_coord0(grid,size,origin=_np.zeros(3)): +def coordinates0_point(cells,size,origin=_np.zeros(3)): """ Cell center positions (undeformed). Parameters ---------- - grid : numpy.ndarray of shape (3) - number of grid points. + cells : numpy.ndarray of shape (3) + Number of cells. size : numpy.ndarray of shape (3) - physical size of the periodic field. + Physical size of the periodic field. origin : numpy.ndarray, optional - physical origin of the periodic field. Defaults to [0.0,0.0,0.0]. + Physical origin of the periodic field. Defaults to [0.0,0.0,0.0]. """ - start = origin + size/grid*.5 - end = origin + size - size/grid*.5 + start = origin + size/cells*.5 + end = origin + size - size/cells*.5 - return _np.stack(_np.meshgrid(_np.linspace(start[0],end[0],grid[0]), - _np.linspace(start[1],end[1],grid[1]), - _np.linspace(start[2],end[2],grid[2]),indexing = 'ij'), + return _np.stack(_np.meshgrid(_np.linspace(start[0],end[0],cells[0]), + _np.linspace(start[1],end[1],cells[1]), + _np.linspace(start[2],end[2],cells[2]),indexing = 'ij'), axis = -1) -def cell_displacement_fluct(size,F): +def displacement_fluct_point(size,F): """ Cell center displacement field from fluctuation part of the deformation gradient field. Parameters ---------- size : numpy.ndarray of shape (3) - physical size of the periodic field. + Physical size of the periodic field. F : numpy.ndarray - deformation gradient field. + Deformation gradient field. """ integrator = 0.5j*size/_np.pi @@ -160,194 +160,196 @@ def cell_displacement_fluct(size,F): return _np.fft.irfftn(displacement,axes=(0,1,2),s=F.shape[:3]) -def cell_displacement_avg(size,F): +def displacement_avg_point(size,F): """ Cell center displacement field from average part of the deformation gradient field. Parameters ---------- size : numpy.ndarray of shape (3) - physical size of the periodic field. + Physical size of the periodic field. F : numpy.ndarray - deformation gradient field. + Deformation gradient field. """ F_avg = _np.average(F,axis=(0,1,2)) - return _np.einsum('ml,ijkl->ijkm',F_avg - _np.eye(3),cell_coord0(F.shape[:3],size)) + return _np.einsum('ml,ijkl->ijkm',F_avg - _np.eye(3),coordinates0_point(F.shape[:3],size)) -def cell_displacement(size,F): +def displacement_point(size,F): """ Cell center displacement field from deformation gradient field. Parameters ---------- size : numpy.ndarray of shape (3) - physical size of the periodic field. + Physical size of the periodic field. F : numpy.ndarray - deformation gradient field. + Deformation gradient field. """ - return cell_displacement_avg(size,F) + cell_displacement_fluct(size,F) + return displacement_avg_point(size,F) + displacement_fluct_point(size,F) -def cell_coord(size,F,origin=_np.zeros(3)): +def coordinates_point(size,F,origin=_np.zeros(3)): """ Cell center positions. Parameters ---------- size : numpy.ndarray of shape (3) - physical size of the periodic field. + Physical size of the periodic field. F : numpy.ndarray - deformation gradient field. + Deformation gradient field. origin : numpy.ndarray of shape (3), optional - physical origin of the periodic field. Defaults to [0.0,0.0,0.0]. + Physical origin of the periodic field. Defaults to [0.0,0.0,0.0]. """ - return cell_coord0(F.shape[:3],size,origin) + cell_displacement(size,F) + return coordinates0_point(F.shape[:3],size,origin) + displacement_point(size,F) -def cell_coord0_gridSizeOrigin(coord0,ordered=True): +def cellsSizeOrigin_coordinates0_point(coordinates0,ordered=True): """ - Return grid 'DNA', i.e. grid, size, and origin from 1D array of cell positions. + Return grid 'DNA', i.e. cells, size, and origin from 1D array of point positions. Parameters ---------- - coord0 : numpy.ndarray of shape (:,3) - undeformed cell coordinates. + coordinates0 : numpy.ndarray of shape (:,3) + Undeformed cell coordinates. ordered : bool, optional - expect coord0 data to be ordered (x fast, z slow). + Expect coordinates0 data to be ordered (x fast, z slow). + Defaults to True. """ - coords = [_np.unique(coord0[:,i]) for i in range(3)] + coords = [_np.unique(coordinates0[:,i]) for i in range(3)] mincorner = _np.array(list(map(min,coords))) maxcorner = _np.array(list(map(max,coords))) - grid = _np.array(list(map(len,coords)),'i') - size = grid/_np.maximum(grid-1,1) * (maxcorner-mincorner) - delta = size/grid + cells = _np.array(list(map(len,coords)),'i') + size = cells/_np.maximum(cells-1,1) * (maxcorner-mincorner) + delta = size/cells origin = mincorner - delta*.5 # 1D/2D: size/origin combination undefined, set origin to 0.0 - size [_np.where(grid==1)] = origin[_np.where(grid==1)]*2. - origin[_np.where(grid==1)] = 0.0 + size [_np.where(cells==1)] = origin[_np.where(cells==1)]*2. + origin[_np.where(cells==1)] = 0.0 - if grid.prod() != len(coord0): - raise ValueError('Data count {len(coord0)} does not match grid {grid}.') + if cells.prod() != len(coordinates0): + raise ValueError(f'Data count {len(coordinates0)} does not match cells {cells}.') start = origin + delta*.5 end = origin - delta*.5 + size atol = _np.max(size)*5e-2 - if not (_np.allclose(coords[0],_np.linspace(start[0],end[0],grid[0]),atol=atol) and \ - _np.allclose(coords[1],_np.linspace(start[1],end[1],grid[1]),atol=atol) and \ - _np.allclose(coords[2],_np.linspace(start[2],end[2],grid[2]),atol=atol)): - raise ValueError('Regular grid spacing violated.') + if not (_np.allclose(coords[0],_np.linspace(start[0],end[0],cells[0]),atol=atol) and \ + _np.allclose(coords[1],_np.linspace(start[1],end[1],cells[1]),atol=atol) and \ + _np.allclose(coords[2],_np.linspace(start[2],end[2],cells[2]),atol=atol)): + raise ValueError('Regular cell spacing violated.') - if ordered and not _np.allclose(coord0.reshape(tuple(grid)+(3,),order='F'),cell_coord0(grid,size,origin),atol=atol): + if ordered and not _np.allclose(coordinates0.reshape(tuple(cells)+(3,),order='F'), + coordinates0_point(cells,size,origin),atol=atol): raise ValueError('Input data is not ordered (x fast, z slow).') - return (grid,size,origin) + return (cells,size,origin) -def coord0_check(coord0): +def coordinates0_check(coordinates0): """ Check whether coordinates lie on a regular grid. Parameters ---------- - coord0 : numpy.ndarray - array of undeformed cell coordinates. + coordinates0 : numpy.ndarray + Array of undeformed cell coordinates. """ - cell_coord0_gridSizeOrigin(coord0,ordered=True) + cellsSizeOrigin_coordinates0_point(coordinates0,ordered=True) -def node_coord0(grid,size,origin=_np.zeros(3)): +def coordinates0_node(cells,size,origin=_np.zeros(3)): """ Nodal positions (undeformed). Parameters ---------- - grid : numpy.ndarray of shape (3) - number of grid points. + cells : numpy.ndarray of shape (3) + Number of cells. size : numpy.ndarray of shape (3) - physical size of the periodic field. + Physical size of the periodic field. origin : numpy.ndarray of shape (3), optional - physical origin of the periodic field. Defaults to [0.0,0.0,0.0]. + Physical origin of the periodic field. Defaults to [0.0,0.0,0.0]. """ - return _np.stack(_np.meshgrid(_np.linspace(origin[0],size[0]+origin[0],grid[0]+1), - _np.linspace(origin[1],size[1]+origin[1],grid[1]+1), - _np.linspace(origin[2],size[2]+origin[2],grid[2]+1),indexing = 'ij'), + return _np.stack(_np.meshgrid(_np.linspace(origin[0],size[0]+origin[0],cells[0]+1), + _np.linspace(origin[1],size[1]+origin[1],cells[1]+1), + _np.linspace(origin[2],size[2]+origin[2],cells[2]+1),indexing = 'ij'), axis = -1) -def node_displacement_fluct(size,F): +def displacement_fluct_node(size,F): """ Nodal displacement field from fluctuation part of the deformation gradient field. Parameters ---------- size : numpy.ndarray of shape (3) - physical size of the periodic field. + Physical size of the periodic field. F : numpy.ndarray - deformation gradient field. + Deformation gradient field. """ - return cell_2_node(cell_displacement_fluct(size,F)) + return point_to_node(displacement_fluct_point(size,F)) -def node_displacement_avg(size,F): +def displacement_avg_node(size,F): """ Nodal displacement field from average part of the deformation gradient field. Parameters ---------- size : numpy.ndarray of shape (3) - physical size of the periodic field. + Physical size of the periodic field. F : numpy.ndarray - deformation gradient field. + Deformation gradient field. """ F_avg = _np.average(F,axis=(0,1,2)) - return _np.einsum('ml,ijkl->ijkm',F_avg - _np.eye(3),node_coord0(F.shape[:3],size)) + return _np.einsum('ml,ijkl->ijkm',F_avg - _np.eye(3),coordinates0_node(F.shape[:3],size)) -def node_displacement(size,F): +def displacement_node(size,F): """ Nodal displacement field from deformation gradient field. Parameters ---------- size : numpy.ndarray of shape (3) - physical size of the periodic field. + Physical size of the periodic field. F : numpy.ndarray - deformation gradient field. + Deformation gradient field. """ - return node_displacement_avg(size,F) + node_displacement_fluct(size,F) + return displacement_avg_node(size,F) + displacement_fluct_node(size,F) -def node_coord(size,F,origin=_np.zeros(3)): +def coordinates_node(size,F,origin=_np.zeros(3)): """ Nodal positions. Parameters ---------- size : numpy.ndarray of shape (3) - physical size of the periodic field. + Physical size of the periodic field. F : numpy.ndarray - deformation gradient field. + Deformation gradient field. origin : numpy.ndarray of shape (3), optional - physical origin of the periodic field. Defaults to [0.0,0.0,0.0]. + Physical origin of the periodic field. Defaults to [0.0,0.0,0.0]. """ - return node_coord0(F.shape[:3],size,origin) + node_displacement(size,F) + return coordinates0_node(F.shape[:3],size,origin) + displacement_node(size,F) -def cell_2_node(cell_data): - """Interpolate periodic cell data to nodal data.""" +def point_to_node(cell_data): + """Interpolate periodic point data to nodal data.""" n = ( cell_data + _np.roll(cell_data,1,(0,1,2)) + _np.roll(cell_data,1,(0,)) + _np.roll(cell_data,1,(1,)) + _np.roll(cell_data,1,(2,)) + _np.roll(cell_data,1,(0,1)) + _np.roll(cell_data,1,(1,2)) + _np.roll(cell_data,1,(2,0)))*0.125 @@ -355,8 +357,8 @@ def cell_2_node(cell_data): return _np.pad(n,((0,1),(0,1),(0,1))+((0,0),)*len(cell_data.shape[3:]),mode='wrap') -def node_2_cell(node_data): - """Interpolate periodic nodal data to cell data.""" +def node_2_point(node_data): + """Interpolate periodic nodal data to point data.""" c = ( node_data + _np.roll(node_data,1,(0,1,2)) + _np.roll(node_data,1,(0,)) + _np.roll(node_data,1,(1,)) + _np.roll(node_data,1,(2,)) + _np.roll(node_data,1,(0,1)) + _np.roll(node_data,1,(1,2)) + _np.roll(node_data,1,(2,0)))*0.125 @@ -364,57 +366,57 @@ def node_2_cell(node_data): return c[1:,1:,1:] -def node_coord0_gridSizeOrigin(coord0,ordered=True): +def cellsSizeOrigin_coordinates0_node(coordinates0,ordered=True): """ - Return grid 'DNA', i.e. grid, size, and origin from 1D array of nodal positions. + Return grid 'DNA', i.e. cells, size, and origin from 1D array of nodal positions. Parameters ---------- - coord0 : numpy.ndarray of shape (:,3) - undeformed nodal coordinates. + coordinates0 : numpy.ndarray of shape (:,3) + Undeformed nodal coordinates. ordered : bool, optional - expect coord0 data to be ordered (x fast, z slow). + Expect coordinates0 data to be ordered (x fast, z slow). + Defaults to True. """ - coords = [_np.unique(coord0[:,i]) for i in range(3)] + coords = [_np.unique(coordinates0[:,i]) for i in range(3)] mincorner = _np.array(list(map(min,coords))) maxcorner = _np.array(list(map(max,coords))) - grid = _np.array(list(map(len,coords)),'i') - 1 + cells = _np.array(list(map(len,coords)),'i') - 1 size = maxcorner-mincorner origin = mincorner - if (grid+1).prod() != len(coord0): - raise ValueError('Data count {len(coord0)} does not match grid {grid}.') + if (cells+1).prod() != len(coordinates0): + raise ValueError(f'Data count {len(coordinates0)} does not match cells {cells}.') atol = _np.max(size)*5e-2 - if not (_np.allclose(coords[0],_np.linspace(mincorner[0],maxcorner[0],grid[0]+1),atol=atol) and \ - _np.allclose(coords[1],_np.linspace(mincorner[1],maxcorner[1],grid[1]+1),atol=atol) and \ - _np.allclose(coords[2],_np.linspace(mincorner[2],maxcorner[2],grid[2]+1),atol=atol)): - raise ValueError('Regular grid spacing violated.') + if not (_np.allclose(coords[0],_np.linspace(mincorner[0],maxcorner[0],cells[0]+1),atol=atol) and \ + _np.allclose(coords[1],_np.linspace(mincorner[1],maxcorner[1],cells[1]+1),atol=atol) and \ + _np.allclose(coords[2],_np.linspace(mincorner[2],maxcorner[2],cells[2]+1),atol=atol)): + raise ValueError('Regular cell spacing violated.') - if ordered and not _np.allclose(coord0.reshape(tuple(grid+1)+(3,),order='F'),node_coord0(grid,size,origin),atol=atol): + if ordered and not _np.allclose(coordinates0.reshape(tuple(cells+1)+(3,),order='F'), + coordinates0_node(cells,size,origin),atol=atol): raise ValueError('Input data is not ordered (x fast, z slow).') - return (grid,size,origin) + return (cells,size,origin) -def regrid(size,F,new_grid): +def regrid(size,F,cells): """ Return mapping from coordinates in deformed configuration to a regular grid. Parameters ---------- size : numpy.ndarray of shape (3) - physical size + Physical size. F : numpy.ndarray of shape (:,:,:,3,3) - deformation gradient field - new_grid : numpy.ndarray of shape (3) - new grid for undeformed coordinates + Deformation gradient field. + cells : numpy.ndarray of shape (3) + Cell count along x,y,z of remapping grid. """ - c = cell_coord0(F.shape[:3],size) \ - + cell_displacement_avg(size,F) \ - + cell_displacement_fluct(size,F) + c = coordinates_point(size,F) outer = _np.dot(_np.average(F,axis=(0,1,2)),size) for d in range(3): @@ -422,4 +424,4 @@ def regrid(size,F,new_grid): c[_np.where(c[:,:,:,d]>outer[d])] -= outer[d] tree = _spatial.cKDTree(c.reshape(-1,3),boxsize=outer) - return tree.query(cell_coord0(new_grid,outer))[1].flatten() + return tree.query(coordinates0_point(cells,outer))[1].flatten() diff --git a/python/damask/seeds.py b/python/damask/seeds.py index 1c4150c2d..9ab148a82 100644 --- a/python/damask/seeds.py +++ b/python/damask/seeds.py @@ -7,7 +7,7 @@ from . import util from . import grid_filters -def from_random(size,N_seeds,grid=None,rng_seed=None): +def from_random(size,N_seeds,cells=None,rng_seed=None): """ Random seeding in space. @@ -17,21 +17,21 @@ def from_random(size,N_seeds,grid=None,rng_seed=None): Physical size of the seeding domain. N_seeds : int Number of seeds. - grid : numpy.ndarray of shape (3), optional. - If given, ensures that all seeds initiate one grain if using a - standard Voronoi tessellation. + cells : numpy.ndarray of shape (3), optional. + If given, ensures that each seed results in a grain when a standard Voronoi + tessellation is performed using the given grid resolution (i.e. size/cells). rng_seed : {None, int, array_like[ints], SeedSequence, BitGenerator, Generator}, optional A seed to initialize the BitGenerator. Defaults to None. If None, then fresh, unpredictable entropy will be pulled from the OS. """ rng = _np.random.default_rng(rng_seed) - if grid is None: + if cells is None: coords = rng.random((N_seeds,3)) * size else: - grid_coords = grid_filters.cell_coord0(grid,size).reshape(-1,3,order='F') - coords = grid_coords[rng.choice(_np.prod(grid),N_seeds, replace=False)] \ - + _np.broadcast_to(size/grid,(N_seeds,3))*(rng.random((N_seeds,3))*.5-.25) # wobble without leaving grid + grid_coords = grid_filters.coordinates0_point(cells,size).reshape(-1,3,order='F') + coords = grid_coords[rng.choice(_np.prod(cells),N_seeds, replace=False)] \ + + _np.broadcast_to(size/cells,(N_seeds,3))*(rng.random((N_seeds,3))*.5-.25) # wobble without leaving cells return coords @@ -77,14 +77,14 @@ def from_Poisson_disc(size,N_seeds,N_candidates,distance,periodic=True,rng_seed= return coords -def from_geom(geom,selection=None,invert=False,average=False,periodic=True): +def from_grid(grid,selection=None,invert=False,average=False,periodic=True): """ - Create seed from existing geometry description. + Create seed from existing grid description. Parameters ---------- - geom : damask.Geom - Geometry, from which the material IDs are used as seeds. + grid : damask.Grid + Grid, from which the material IDs are used as seeds. selection : iterable of integers, optional Material IDs to consider. invert : boolean, false @@ -95,10 +95,10 @@ def from_geom(geom,selection=None,invert=False,average=False,periodic=True): Center of gravity with periodic boundaries. """ - material = geom.material.reshape((-1,1),order='F') - mask = _np.full(geom.grid.prod(),True,dtype=bool) if selection is None else \ + material = grid.material.reshape((-1,1),order='F') + mask = _np.full(grid.cells.prod(),True,dtype=bool) if selection is None else \ _np.isin(material,selection,invert=invert).flatten() - coords = grid_filters.cell_coord0(geom.grid,geom.size).reshape(-1,3,order='F') + coords = grid_filters.coordinates0_point(grid.cells,grid.size).reshape(-1,3,order='F') if not average: return (coords[mask],material[mask]) @@ -106,8 +106,8 @@ def from_geom(geom,selection=None,invert=False,average=False,periodic=True): materials = _np.unique(material[mask]) coords_ = _np.zeros((materials.size,3),dtype=float) for i,mat in enumerate(materials): - pc = (2*_np.pi*coords[material[:,0]==mat,:]-geom.origin)/geom.size - coords_[i] = geom.origin + geom.size / 2 / _np.pi * (_np.pi + + pc = (2*_np.pi*coords[material[:,0]==mat,:]-grid.origin)/grid.size + coords_[i] = grid.origin + grid.size / 2 / _np.pi * (_np.pi + _np.arctan2(-_np.average(_np.sin(pc),axis=0), -_np.average(_np.cos(pc),axis=0))) \ if periodic else \ diff --git a/python/tests/reference/ConfigMaterial/material.yaml b/python/tests/reference/ConfigMaterial/material.yaml index 933e295b3..fbba6a631 100644 --- a/python/tests/reference/ConfigMaterial/material.yaml +++ b/python/tests/reference/ConfigMaterial/material.yaml @@ -1,10 +1,10 @@ homogenization: SX: - N_constituents: 2 - mech: {type: none} + N_constituents: 1 + mechanics: {type: none} Taylor: N_constituents: 2 - mech: {type: isostrain} + mechanics: {type: isostrain} material: - constituents: @@ -34,11 +34,11 @@ material: phase: Aluminum: lattice: cF - mech: + mechanics: output: [F, P, F_e, F_p, L_p] elasticity: {C_11: 106.75e9, C_12: 60.41e9, C_44: 28.34e9, type: hooke} Steel: lattice: cI - mech: + mechanics: output: [F, P, F_e, F_p, L_p] elasticity: {C_11: 233.3e9, C_12: 135.5e9, C_44: 118.0e9, type: hooke} diff --git a/python/tests/reference/Geom/clean_1_1+2+3_False.vtr b/python/tests/reference/Grid/clean_1_1+2+3_False.vtr similarity index 100% rename from python/tests/reference/Geom/clean_1_1+2+3_False.vtr rename to python/tests/reference/Grid/clean_1_1+2+3_False.vtr diff --git a/python/tests/reference/Geom/clean_1_1+2+3_True.vtr b/python/tests/reference/Grid/clean_1_1+2+3_True.vtr similarity index 100% rename from python/tests/reference/Geom/clean_1_1+2+3_True.vtr rename to python/tests/reference/Grid/clean_1_1+2+3_True.vtr diff --git a/python/tests/reference/Geom/clean_1_1_False.vtr b/python/tests/reference/Grid/clean_1_1_False.vtr similarity index 100% rename from python/tests/reference/Geom/clean_1_1_False.vtr rename to python/tests/reference/Grid/clean_1_1_False.vtr diff --git a/python/tests/reference/Geom/clean_1_1_True.vtr b/python/tests/reference/Grid/clean_1_1_True.vtr similarity index 100% rename from python/tests/reference/Geom/clean_1_1_True.vtr rename to python/tests/reference/Grid/clean_1_1_True.vtr diff --git a/python/tests/reference/Geom/clean_1_None_False.vtr b/python/tests/reference/Grid/clean_1_None_False.vtr similarity index 100% rename from python/tests/reference/Geom/clean_1_None_False.vtr rename to python/tests/reference/Grid/clean_1_None_False.vtr diff --git a/python/tests/reference/Geom/clean_1_None_True.vtr b/python/tests/reference/Grid/clean_1_None_True.vtr similarity index 100% rename from python/tests/reference/Geom/clean_1_None_True.vtr rename to python/tests/reference/Grid/clean_1_None_True.vtr diff --git a/python/tests/reference/Geom/clean_2_1+2+3_False.vtr b/python/tests/reference/Grid/clean_2_1+2+3_False.vtr similarity index 100% rename from python/tests/reference/Geom/clean_2_1+2+3_False.vtr rename to python/tests/reference/Grid/clean_2_1+2+3_False.vtr diff --git a/python/tests/reference/Geom/clean_2_1+2+3_True.vtr b/python/tests/reference/Grid/clean_2_1+2+3_True.vtr similarity index 100% rename from python/tests/reference/Geom/clean_2_1+2+3_True.vtr rename to python/tests/reference/Grid/clean_2_1+2+3_True.vtr diff --git a/python/tests/reference/Geom/clean_2_1_False.vtr b/python/tests/reference/Grid/clean_2_1_False.vtr similarity index 100% rename from python/tests/reference/Geom/clean_2_1_False.vtr rename to python/tests/reference/Grid/clean_2_1_False.vtr diff --git a/python/tests/reference/Geom/clean_2_1_True.vtr b/python/tests/reference/Grid/clean_2_1_True.vtr similarity index 100% rename from python/tests/reference/Geom/clean_2_1_True.vtr rename to python/tests/reference/Grid/clean_2_1_True.vtr diff --git a/python/tests/reference/Geom/clean_2_2_False.vtr b/python/tests/reference/Grid/clean_2_2_False.vtr similarity index 100% rename from python/tests/reference/Geom/clean_2_2_False.vtr rename to python/tests/reference/Grid/clean_2_2_False.vtr diff --git a/python/tests/reference/Geom/clean_2_2_True.vtr b/python/tests/reference/Grid/clean_2_2_True.vtr similarity index 100% rename from python/tests/reference/Geom/clean_2_2_True.vtr rename to python/tests/reference/Grid/clean_2_2_True.vtr diff --git a/python/tests/reference/Geom/clean_2_None_False.vtr b/python/tests/reference/Grid/clean_2_None_False.vtr similarity index 100% rename from python/tests/reference/Geom/clean_2_None_False.vtr rename to python/tests/reference/Grid/clean_2_None_False.vtr diff --git a/python/tests/reference/Geom/clean_2_None_True.vtr b/python/tests/reference/Grid/clean_2_None_True.vtr similarity index 100% rename from python/tests/reference/Geom/clean_2_None_True.vtr rename to python/tests/reference/Grid/clean_2_None_True.vtr diff --git a/python/tests/reference/Geom/clean_3_1+2+3_False.vtr b/python/tests/reference/Grid/clean_3_1+2+3_False.vtr similarity index 100% rename from python/tests/reference/Geom/clean_3_1+2+3_False.vtr rename to python/tests/reference/Grid/clean_3_1+2+3_False.vtr diff --git a/python/tests/reference/Geom/clean_3_1+2+3_True.vtr b/python/tests/reference/Grid/clean_3_1+2+3_True.vtr similarity index 100% rename from python/tests/reference/Geom/clean_3_1+2+3_True.vtr rename to python/tests/reference/Grid/clean_3_1+2+3_True.vtr diff --git a/python/tests/reference/Geom/clean_3_1_False.vtr b/python/tests/reference/Grid/clean_3_1_False.vtr similarity index 100% rename from python/tests/reference/Geom/clean_3_1_False.vtr rename to python/tests/reference/Grid/clean_3_1_False.vtr diff --git a/python/tests/reference/Geom/clean_3_1_True.vtr b/python/tests/reference/Grid/clean_3_1_True.vtr similarity index 100% rename from python/tests/reference/Geom/clean_3_1_True.vtr rename to python/tests/reference/Grid/clean_3_1_True.vtr diff --git a/python/tests/reference/Geom/clean_3_2_False.vtr b/python/tests/reference/Grid/clean_3_2_False.vtr similarity index 100% rename from python/tests/reference/Geom/clean_3_2_False.vtr rename to python/tests/reference/Grid/clean_3_2_False.vtr diff --git a/python/tests/reference/Geom/clean_3_2_True.vtr b/python/tests/reference/Grid/clean_3_2_True.vtr similarity index 100% rename from python/tests/reference/Geom/clean_3_2_True.vtr rename to python/tests/reference/Grid/clean_3_2_True.vtr diff --git a/python/tests/reference/Geom/clean_3_None_False.vtr b/python/tests/reference/Grid/clean_3_None_False.vtr similarity index 100% rename from python/tests/reference/Geom/clean_3_None_False.vtr rename to python/tests/reference/Grid/clean_3_None_False.vtr diff --git a/python/tests/reference/Geom/clean_3_None_True.vtr b/python/tests/reference/Grid/clean_3_None_True.vtr similarity index 100% rename from python/tests/reference/Geom/clean_3_None_True.vtr rename to python/tests/reference/Grid/clean_3_None_True.vtr diff --git a/python/tests/reference/Geom/clean_4_1+2+3_False.vtr b/python/tests/reference/Grid/clean_4_1+2+3_False.vtr similarity index 100% rename from python/tests/reference/Geom/clean_4_1+2+3_False.vtr rename to python/tests/reference/Grid/clean_4_1+2+3_False.vtr diff --git a/python/tests/reference/Geom/clean_4_1+2+3_True.vtr b/python/tests/reference/Grid/clean_4_1+2+3_True.vtr similarity index 100% rename from python/tests/reference/Geom/clean_4_1+2+3_True.vtr rename to python/tests/reference/Grid/clean_4_1+2+3_True.vtr diff --git a/python/tests/reference/Geom/clean_4_1_False.vtr b/python/tests/reference/Grid/clean_4_1_False.vtr similarity index 100% rename from python/tests/reference/Geom/clean_4_1_False.vtr rename to python/tests/reference/Grid/clean_4_1_False.vtr diff --git a/python/tests/reference/Geom/clean_4_1_True.vtr b/python/tests/reference/Grid/clean_4_1_True.vtr similarity index 100% rename from python/tests/reference/Geom/clean_4_1_True.vtr rename to python/tests/reference/Grid/clean_4_1_True.vtr diff --git a/python/tests/reference/Geom/clean_4_2_False.vtr b/python/tests/reference/Grid/clean_4_2_False.vtr similarity index 100% rename from python/tests/reference/Geom/clean_4_2_False.vtr rename to python/tests/reference/Grid/clean_4_2_False.vtr diff --git a/python/tests/reference/Geom/clean_4_2_True.vtr b/python/tests/reference/Grid/clean_4_2_True.vtr similarity index 100% rename from python/tests/reference/Geom/clean_4_2_True.vtr rename to python/tests/reference/Grid/clean_4_2_True.vtr diff --git a/python/tests/reference/Geom/clean_4_None_False.vtr b/python/tests/reference/Grid/clean_4_None_False.vtr similarity index 100% rename from python/tests/reference/Geom/clean_4_None_False.vtr rename to python/tests/reference/Grid/clean_4_None_False.vtr diff --git a/python/tests/reference/Geom/clean_4_None_True.vtr b/python/tests/reference/Grid/clean_4_None_True.vtr similarity index 100% rename from python/tests/reference/Geom/clean_4_None_True.vtr rename to python/tests/reference/Grid/clean_4_None_True.vtr diff --git a/python/tests/reference/Geom/flip_directions_x-y-z.vtr b/python/tests/reference/Grid/flip_directions_x-y-z.vtr similarity index 100% rename from python/tests/reference/Geom/flip_directions_x-y-z.vtr rename to python/tests/reference/Grid/flip_directions_x-y-z.vtr diff --git a/python/tests/reference/Geom/flip_directions_x.vtr b/python/tests/reference/Grid/flip_directions_x.vtr similarity index 100% rename from python/tests/reference/Geom/flip_directions_x.vtr rename to python/tests/reference/Grid/flip_directions_x.vtr diff --git a/python/tests/reference/Geom/flip_directions_y-z.vtr b/python/tests/reference/Grid/flip_directions_y-z.vtr similarity index 100% rename from python/tests/reference/Geom/flip_directions_y-z.vtr rename to python/tests/reference/Grid/flip_directions_y-z.vtr diff --git a/python/tests/reference/Geom/flip_directions_z-x-y.vtr b/python/tests/reference/Grid/flip_directions_z-x-y.vtr similarity index 100% rename from python/tests/reference/Geom/flip_directions_z-x-y.vtr rename to python/tests/reference/Grid/flip_directions_z-x-y.vtr diff --git a/python/tests/reference/Geom/get_grain_boundaries_8g12x15x20.vtr b/python/tests/reference/Grid/get_grain_boundaries_8g12x15x20.vtr similarity index 100% rename from python/tests/reference/Geom/get_grain_boundaries_8g12x15x20.vtr rename to python/tests/reference/Grid/get_grain_boundaries_8g12x15x20.vtr diff --git a/python/tests/reference/Geom/get_grain_boundaries_8g12x15x20_x_False.vtu b/python/tests/reference/Grid/get_grain_boundaries_8g12x15x20_x_False.vtu similarity index 100% rename from python/tests/reference/Geom/get_grain_boundaries_8g12x15x20_x_False.vtu rename to python/tests/reference/Grid/get_grain_boundaries_8g12x15x20_x_False.vtu diff --git a/python/tests/reference/Geom/get_grain_boundaries_8g12x15x20_x_True.vtu b/python/tests/reference/Grid/get_grain_boundaries_8g12x15x20_x_True.vtu similarity index 100% rename from python/tests/reference/Geom/get_grain_boundaries_8g12x15x20_x_True.vtu rename to python/tests/reference/Grid/get_grain_boundaries_8g12x15x20_x_True.vtu diff --git a/python/tests/reference/Geom/get_grain_boundaries_8g12x15x20_xy_False.vtu b/python/tests/reference/Grid/get_grain_boundaries_8g12x15x20_xy_False.vtu similarity index 100% rename from python/tests/reference/Geom/get_grain_boundaries_8g12x15x20_xy_False.vtu rename to python/tests/reference/Grid/get_grain_boundaries_8g12x15x20_xy_False.vtu diff --git a/python/tests/reference/Geom/get_grain_boundaries_8g12x15x20_xy_True.vtu b/python/tests/reference/Grid/get_grain_boundaries_8g12x15x20_xy_True.vtu similarity index 100% rename from python/tests/reference/Geom/get_grain_boundaries_8g12x15x20_xy_True.vtu rename to python/tests/reference/Grid/get_grain_boundaries_8g12x15x20_xy_True.vtu diff --git a/python/tests/reference/Geom/get_grain_boundaries_8g12x15x20_xyz_False.vtu b/python/tests/reference/Grid/get_grain_boundaries_8g12x15x20_xyz_False.vtu similarity index 100% rename from python/tests/reference/Geom/get_grain_boundaries_8g12x15x20_xyz_False.vtu rename to python/tests/reference/Grid/get_grain_boundaries_8g12x15x20_xyz_False.vtu diff --git a/python/tests/reference/Geom/get_grain_boundaries_8g12x15x20_xyz_True.vtu b/python/tests/reference/Grid/get_grain_boundaries_8g12x15x20_xyz_True.vtu similarity index 100% rename from python/tests/reference/Geom/get_grain_boundaries_8g12x15x20_xyz_True.vtu rename to python/tests/reference/Grid/get_grain_boundaries_8g12x15x20_xyz_True.vtu diff --git a/python/tests/reference/Geom/get_grain_boundaries_8g12x15x20_xz_False.vtu b/python/tests/reference/Grid/get_grain_boundaries_8g12x15x20_xz_False.vtu similarity index 100% rename from python/tests/reference/Geom/get_grain_boundaries_8g12x15x20_xz_False.vtu rename to python/tests/reference/Grid/get_grain_boundaries_8g12x15x20_xz_False.vtu diff --git a/python/tests/reference/Geom/get_grain_boundaries_8g12x15x20_xz_True.vtu b/python/tests/reference/Grid/get_grain_boundaries_8g12x15x20_xz_True.vtu similarity index 100% rename from python/tests/reference/Geom/get_grain_boundaries_8g12x15x20_xz_True.vtu rename to python/tests/reference/Grid/get_grain_boundaries_8g12x15x20_xz_True.vtu diff --git a/python/tests/reference/Geom/get_grain_boundaries_8g12x15x20_y_False.vtu b/python/tests/reference/Grid/get_grain_boundaries_8g12x15x20_y_False.vtu similarity index 100% rename from python/tests/reference/Geom/get_grain_boundaries_8g12x15x20_y_False.vtu rename to python/tests/reference/Grid/get_grain_boundaries_8g12x15x20_y_False.vtu diff --git a/python/tests/reference/Geom/get_grain_boundaries_8g12x15x20_y_True.vtu b/python/tests/reference/Grid/get_grain_boundaries_8g12x15x20_y_True.vtu similarity index 100% rename from python/tests/reference/Geom/get_grain_boundaries_8g12x15x20_y_True.vtu rename to python/tests/reference/Grid/get_grain_boundaries_8g12x15x20_y_True.vtu diff --git a/python/tests/reference/Geom/get_grain_boundaries_8g12x15x20_z_False.vtu b/python/tests/reference/Grid/get_grain_boundaries_8g12x15x20_z_False.vtu similarity index 100% rename from python/tests/reference/Geom/get_grain_boundaries_8g12x15x20_z_False.vtu rename to python/tests/reference/Grid/get_grain_boundaries_8g12x15x20_z_False.vtu diff --git a/python/tests/reference/Geom/get_grain_boundaries_8g12x15x20_z_True.vtu b/python/tests/reference/Grid/get_grain_boundaries_8g12x15x20_z_True.vtu similarity index 100% rename from python/tests/reference/Geom/get_grain_boundaries_8g12x15x20_z_True.vtu rename to python/tests/reference/Grid/get_grain_boundaries_8g12x15x20_z_True.vtu diff --git a/python/tests/reference/Geom/get_grain_boundaries_8g12x15x20_zy_False.vtu b/python/tests/reference/Grid/get_grain_boundaries_8g12x15x20_zy_False.vtu similarity index 100% rename from python/tests/reference/Geom/get_grain_boundaries_8g12x15x20_zy_False.vtu rename to python/tests/reference/Grid/get_grain_boundaries_8g12x15x20_zy_False.vtu diff --git a/python/tests/reference/Geom/get_grain_boundaries_8g12x15x20_zy_True.vtu b/python/tests/reference/Grid/get_grain_boundaries_8g12x15x20_zy_True.vtu similarity index 100% rename from python/tests/reference/Geom/get_grain_boundaries_8g12x15x20_zy_True.vtu rename to python/tests/reference/Grid/get_grain_boundaries_8g12x15x20_zy_True.vtu diff --git a/python/tests/reference/Geom/mirror_directions_x+reflect_False.vtr b/python/tests/reference/Grid/mirror_directions_x+reflect_False.vtr similarity index 100% rename from python/tests/reference/Geom/mirror_directions_x+reflect_False.vtr rename to python/tests/reference/Grid/mirror_directions_x+reflect_False.vtr diff --git a/python/tests/reference/Geom/mirror_directions_x-y-z+reflect_True.vtr b/python/tests/reference/Grid/mirror_directions_x-y-z+reflect_True.vtr similarity index 100% rename from python/tests/reference/Geom/mirror_directions_x-y-z+reflect_True.vtr rename to python/tests/reference/Grid/mirror_directions_x-y-z+reflect_True.vtr diff --git a/python/tests/reference/Geom/mirror_directions_y-z+reflect_False.vtr b/python/tests/reference/Grid/mirror_directions_y-z+reflect_False.vtr similarity index 100% rename from python/tests/reference/Geom/mirror_directions_y-z+reflect_False.vtr rename to python/tests/reference/Grid/mirror_directions_y-z+reflect_False.vtr diff --git a/python/tests/reference/Geom/mirror_directions_z-x-y+reflect_False.vtr b/python/tests/reference/Grid/mirror_directions_z-x-y+reflect_False.vtr similarity index 100% rename from python/tests/reference/Geom/mirror_directions_z-x-y+reflect_False.vtr rename to python/tests/reference/Grid/mirror_directions_z-x-y+reflect_False.vtr diff --git a/python/tests/reference/Geom/rotate_Eulers_0.0-32.0-240.0.vtr b/python/tests/reference/Grid/rotate_Eulers_0.0-32.0-240.0.vtr similarity index 100% rename from python/tests/reference/Geom/rotate_Eulers_0.0-32.0-240.0.vtr rename to python/tests/reference/Grid/rotate_Eulers_0.0-32.0-240.0.vtr diff --git a/python/tests/reference/Geom/rotate_Eulers_32.0-68.0-21.0.vtr b/python/tests/reference/Grid/rotate_Eulers_32.0-68.0-21.0.vtr similarity index 100% rename from python/tests/reference/Geom/rotate_Eulers_32.0-68.0-21.0.vtr rename to python/tests/reference/Grid/rotate_Eulers_32.0-68.0-21.0.vtr diff --git a/python/tests/reference/Geom/scale_grid_10-10-10.vtr b/python/tests/reference/Grid/scale_grid_10-10-10.vtr similarity index 100% rename from python/tests/reference/Geom/scale_grid_10-10-10.vtr rename to python/tests/reference/Grid/scale_grid_10-10-10.vtr diff --git a/python/tests/reference/Geom/scale_grid_10-11-10.vtr b/python/tests/reference/Grid/scale_grid_10-11-10.vtr similarity index 100% rename from python/tests/reference/Geom/scale_grid_10-11-10.vtr rename to python/tests/reference/Grid/scale_grid_10-11-10.vtr diff --git a/python/tests/reference/Geom/scale_grid_10-13-10.vtr b/python/tests/reference/Grid/scale_grid_10-13-10.vtr similarity index 100% rename from python/tests/reference/Geom/scale_grid_10-13-10.vtr rename to python/tests/reference/Grid/scale_grid_10-13-10.vtr diff --git a/python/tests/reference/Geom/scale_grid_10-20-2.vtr b/python/tests/reference/Grid/scale_grid_10-20-2.vtr similarity index 100% rename from python/tests/reference/Geom/scale_grid_10-20-2.vtr rename to python/tests/reference/Grid/scale_grid_10-20-2.vtr diff --git a/python/tests/reference/Geom/scale_grid_5-4-20.vtr b/python/tests/reference/Grid/scale_grid_5-4-20.vtr similarity index 100% rename from python/tests/reference/Geom/scale_grid_5-4-20.vtr rename to python/tests/reference/Grid/scale_grid_5-4-20.vtr diff --git a/python/tests/reference/Geom/scale_grid_8-10-12.vtr b/python/tests/reference/Grid/scale_grid_8-10-12.vtr similarity index 100% rename from python/tests/reference/Geom/scale_grid_8-10-12.vtr rename to python/tests/reference/Grid/scale_grid_8-10-12.vtr diff --git a/python/tests/test_Geom.py b/python/tests/test_Grid.py similarity index 72% rename from python/tests/test_Geom.py rename to python/tests/test_Grid.py index 85da049fa..48831f917 100644 --- a/python/tests/test_Geom.py +++ b/python/tests/test_Grid.py @@ -1,8 +1,9 @@ import pytest import numpy as np +from vtk.util.numpy_support import numpy_to_vtk as np_to_vtk from damask import VTK -from damask import Geom +from damask import Grid from damask import Table from damask import Rotation from damask import util @@ -10,9 +11,9 @@ from damask import seeds from damask import grid_filters -def geom_equal(a,b): +def grid_equal(a,b): return np.all(a.material == b.material) and \ - np.all(a.grid == b.grid) and \ + np.all(a.cells == b.cells) and \ np.allclose(a.size, b.size) and \ str(a.diff(b)) == str(b.diff(a)) @@ -23,15 +24,15 @@ def default(): np.arange(2,42), np.ones(40,dtype=int)*2, np.arange(1,41))).reshape(8,5,4,order='F') - return Geom(x,[8e-6,5e-6,4e-6]) + return Grid(x,[8e-6,5e-6,4e-6]) @pytest.fixture def ref_path(ref_path_base): """Directory containing reference results.""" - return ref_path_base/'Geom' + return ref_path_base/'Grid' -class TestGeom: +class TestGrid: @pytest.fixture(autouse=True) def _patch_execution_stamp(self, patch_execution_stamp): @@ -46,7 +47,7 @@ class TestGeom: def test_diff_not_equal(self,default): - new = Geom(default.material[1:,1:,1:]+1,default.size*.9,np.ones(3)-default.origin,comments=['modified']) + new = Grid(default.material[1:,1:,1:]+1,default.size*.9,np.ones(3)-default.origin,comments=['modified']) assert str(default.diff(new)) != '' def test_repr(self,default): @@ -54,36 +55,44 @@ class TestGeom: def test_read_write_vtr(self,default,tmp_path): default.save(tmp_path/'default') - new = Geom.load(tmp_path/'default.vtr') - assert geom_equal(new,default) + new = Grid.load(tmp_path/'default.vtr') + assert grid_equal(new,default) - def test_invalid_vtr(self,tmp_path): + def test_invalid_no_material(self,tmp_path): v = VTK.from_rectilinear_grid(np.random.randint(5,10,3)*2,np.random.random(3) + 1.0) v.save(tmp_path/'no_materialpoint.vtr',parallel=False) with pytest.raises(ValueError): - Geom.load(tmp_path/'no_materialpoint.vtr') + Grid.load(tmp_path/'no_materialpoint.vtr') - def test_invalid_material(self): + def test_invalid_spacing(self,tmp_path,default): + default.save(tmp_path/'spacing_ok.vtr') + vtk = VTK.load(tmp_path/'spacing_ok.vtr') + vtk.vtk_data.SetXCoordinates(np_to_vtk(np.sort(np.random.random(default.cells[0])))) + vtk.save(tmp_path/'invalid_spacing.vtr',parallel=False) + with pytest.raises(ValueError): + Grid.load(tmp_path/'invalid_spacing.vtr') + + def test_invalid_material_type(self): with pytest.raises(TypeError): - Geom(np.zeros((3,3,3),dtype='complex'),np.ones(3)) + Grid(np.zeros((3,3,3),dtype='complex'),np.ones(3)) def test_cast_to_int(self): - g = Geom(np.zeros((3,3,3)),np.ones(3)) + g = Grid(np.zeros((3,3,3)),np.ones(3)) assert g.material.dtype in np.sctypes['int'] def test_invalid_size(self,default): with pytest.raises(ValueError): - Geom(default.material[1:,1:,1:], + Grid(default.material[1:,1:,1:], size=np.ones(2)) def test_save_load_ASCII(self,default,tmp_path): default.save_ASCII(tmp_path/'ASCII') default.material -= 1 - assert geom_equal(Geom.load_ASCII(tmp_path/'ASCII'),default) + assert grid_equal(Grid.load_ASCII(tmp_path/'ASCII'),default) def test_invalid_origin(self,default): with pytest.raises(ValueError): - Geom(default.material[1:,1:,1:], + Grid(default.material[1:,1:,1:], size=np.ones(3), origin=np.ones(4)) @@ -91,14 +100,14 @@ class TestGeom: def test_invalid_materials_shape(self,default): material = np.ones((3,3)) with pytest.raises(ValueError): - Geom(material, + Grid(material, size=np.ones(3)) def test_invalid_materials_type(self,default): material = np.random.randint(1,300,(3,4,5))==1 with pytest.raises(TypeError): - Geom(material) + Grid(material) @pytest.mark.parametrize('directions,reflect',[ @@ -113,7 +122,7 @@ class TestGeom: tag = f'directions_{"-".join(directions)}+reflect_{reflect}' reference = ref_path/f'mirror_{tag}.vtr' if update: modified.save(reference) - assert geom_equal(Geom.load(reference), + assert grid_equal(Grid.load(reference), modified) @@ -135,17 +144,17 @@ class TestGeom: tag = f'directions_{"-".join(directions)}' reference = ref_path/f'flip_{tag}.vtr' if update: modified.save(reference) - assert geom_equal(Geom.load(reference), + assert grid_equal(Grid.load(reference), modified) def test_flip_invariant(self,default): - assert geom_equal(default,default.flip([])) + assert grid_equal(default,default.flip([])) @pytest.mark.parametrize('direction',[['x'],['x','y']]) def test_flip_double(self,default,direction): - assert geom_equal(default,default.flip(direction).flip(direction)) + assert grid_equal(default,default.flip(direction).flip(direction)) @pytest.mark.parametrize('directions',[(1,2,'y'),('a','b','x'),[1]]) @@ -162,12 +171,12 @@ class TestGeom: reference = ref_path/f'clean_{stencil}_{"+".join(map(str,[None] if selection is None else selection))}_{periodic}' if update and stencil > 1: current.save(reference) - assert geom_equal(Geom.load(reference) if stencil > 1 else default, + assert grid_equal(Grid.load(reference) if stencil > 1 else default, current ) - @pytest.mark.parametrize('grid',[ + @pytest.mark.parametrize('cells',[ (10,11,10), [10,13,10], np.array((10,10,10)), @@ -176,12 +185,12 @@ class TestGeom: np.array((10,20,2)) ] ) - def test_scale(self,default,update,ref_path,grid): - modified = default.scale(grid) - tag = f'grid_{util.srepr(grid,"-")}' + def test_scale(self,default,update,ref_path,cells): + modified = default.scale(cells) + tag = f'grid_{util.srepr(cells,"-")}' reference = ref_path/f'scale_{tag}.vtr' if update: modified.save(reference) - assert geom_equal(Geom.load(reference), + assert grid_equal(Grid.load(reference), modified) @@ -190,21 +199,21 @@ class TestGeom: for m in np.unique(material): material[material==m] = material.max() + np.random.randint(1,30) default.material -= 1 - modified = Geom(material, + modified = Grid(material, default.size, default.origin) - assert not geom_equal(modified,default) - assert geom_equal(default, + assert not grid_equal(modified,default) + assert grid_equal(default, modified.renumber()) def test_substitute(self,default): offset = np.random.randint(1,500) - modified = Geom(default.material + offset, + modified = Grid(default.material + offset, default.size, default.origin) - assert not geom_equal(modified,default) - assert geom_equal(default, + assert not grid_equal(modified,default) + assert grid_equal(default, modified.substitute(np.arange(default.material.max())+1+offset, np.arange(default.material.max())+1)) @@ -212,12 +221,12 @@ class TestGeom: f = np.unique(default.material.flatten())[:np.random.randint(1,default.material.max())] t = np.random.permutation(f) modified = default.substitute(f,t) - assert np.array_equiv(t,f) or (not geom_equal(modified,default)) - assert geom_equal(default, modified.substitute(t,f)) + assert np.array_equiv(t,f) or (not grid_equal(modified,default)) + assert grid_equal(default, modified.substitute(t,f)) def test_sort(self): - grid = np.random.randint(5,20,3) - m = Geom(np.random.randint(1,20,grid)*3,np.ones(3)).sort().material.flatten(order='F') + cells = np.random.randint(5,20,3) + m = Grid(np.random.randint(1,20,cells)*3,np.ones(3)).sort().material.flatten(order='F') for i,v in enumerate(m): assert i==0 or v > m[:i].max() or v in m[:i] @@ -227,7 +236,7 @@ class TestGeom: modified = default.copy() for i in range(np.rint(360/axis_angle[3]).astype(int)): modified.rotate(Rotation.from_axis_angle(axis_angle,degrees=True)) - assert geom_equal(default,modified) + assert grid_equal(default,modified) @pytest.mark.parametrize('Eulers',[[32.0,68.0,21.0], @@ -237,15 +246,15 @@ class TestGeom: tag = f'Eulers_{util.srepr(Eulers,"-")}' reference = ref_path/f'rotate_{tag}.vtr' if update: modified.save(reference) - assert geom_equal(Geom.load(reference), + assert grid_equal(Grid.load(reference), modified) def test_canvas(self,default): - grid = default.grid + cells = default.cells grid_add = np.random.randint(0,30,(3)) - modified = default.canvas(grid + grid_add) - assert np.all(modified.material[:grid[0],:grid[1],:grid[2]] == default.material) + modified = default.canvas(cells + grid_add) + assert np.all(modified.material[:cells[0],:cells[1],:cells[2]] == default.material) @pytest.mark.parametrize('center1,center2',[(np.random.random(3)*.5,np.random.random()*8), @@ -263,8 +272,8 @@ class TestGeom: o = np.random.random(3)-.5 g = np.random.randint(8,32,(3)) s = np.random.random(3)+.5 - G_1 = Geom(np.ones(g,'i'),s,o).add_primitive(diameter,center1,exponent) - G_2 = Geom(np.ones(g,'i'),s,o).add_primitive(diameter,center2,exponent) + G_1 = Grid(np.ones(g,'i'),s,o).add_primitive(diameter,center1,exponent) + G_2 = Grid(np.ones(g,'i'),s,o).add_primitive(diameter,center2,exponent) assert np.count_nonzero(G_1.material!=2) == np.count_nonzero(G_2.material!=2) @@ -279,9 +288,9 @@ class TestGeom: g = np.random.randint(8,32,(3)) s = np.random.random(3)+.5 fill = np.random.randint(10)+2 - G_1 = Geom(np.ones(g,'i'),s).add_primitive(.3,center,1,fill,inverse=inverse,periodic=periodic) - G_2 = Geom(np.ones(g,'i'),s).add_primitive(.3,center,1,fill,Rotation.from_random(),inverse,periodic=periodic) - assert geom_equal(G_1,G_2) + G_1 = Grid(np.ones(g,'i'),s).add_primitive(.3,center,1,fill,inverse=inverse,periodic=periodic) + G_2 = Grid(np.ones(g,'i'),s).add_primitive(.3,center,1,fill,Rotation.from_random(),inverse,periodic=periodic) + assert grid_equal(G_1,G_2) @pytest.mark.parametrize('trigger',[[1],[]]) @@ -300,9 +309,9 @@ class TestGeom: if len(trigger) > 0: m2[m==1] = 1 - geom = Geom(m,np.random.rand(3)).vicinity_offset(vicinity,offset,trigger=trigger) + grid = Grid(m,np.random.rand(3)).vicinity_offset(vicinity,offset,trigger=trigger) - assert np.all(m2==geom.material) + assert np.all(m2==grid.material) @pytest.mark.parametrize('periodic',[True,False]) @@ -314,39 +323,39 @@ class TestGeom: @pytest.mark.parametrize('periodic',[True,False]) def test_tessellation_approaches(self,periodic): - grid = np.random.randint(10,20,3) + cells = np.random.randint(10,20,3) size = np.random.random(3) + 1.0 N_seeds= np.random.randint(10,30) seeds = np.random.rand(N_seeds,3) * np.broadcast_to(size,(N_seeds,3)) - Voronoi = Geom.from_Voronoi_tessellation( grid,size,seeds, np.arange(N_seeds)+5,periodic) - Laguerre = Geom.from_Laguerre_tessellation(grid,size,seeds,np.ones(N_seeds),np.arange(N_seeds)+5,periodic) - assert geom_equal(Laguerre,Voronoi) + Voronoi = Grid.from_Voronoi_tessellation( cells,size,seeds, np.arange(N_seeds)+5,periodic) + Laguerre = Grid.from_Laguerre_tessellation(cells,size,seeds,np.ones(N_seeds),np.arange(N_seeds)+5,periodic) + assert grid_equal(Laguerre,Voronoi) def test_Laguerre_weights(self): - grid = np.random.randint(10,20,3) + cells = np.random.randint(10,20,3) size = np.random.random(3) + 1.0 N_seeds= np.random.randint(10,30) seeds = np.random.rand(N_seeds,3) * np.broadcast_to(size,(N_seeds,3)) weights= np.full((N_seeds),-np.inf) ms = np.random.randint(N_seeds) weights[ms] = np.random.random() - Laguerre = Geom.from_Laguerre_tessellation(grid,size,seeds,weights,periodic=np.random.random()>0.5) + Laguerre = Grid.from_Laguerre_tessellation(cells,size,seeds,weights,periodic=np.random.random()>0.5) assert np.all(Laguerre.material == ms) @pytest.mark.parametrize('approach',['Laguerre','Voronoi']) def test_tessellate_bicrystal(self,approach): - grid = np.random.randint(5,10,3)*2 - size = grid.astype(np.float) + cells = np.random.randint(5,10,3)*2 + size = cells.astype(np.float) seeds = np.vstack((size*np.array([0.5,0.25,0.5]),size*np.array([0.5,0.75,0.5]))) - material = np.zeros(grid) - material[:,grid[1]//2:,:] = 1 + material = np.zeros(cells) + material[:,cells[1]//2:,:] = 1 if approach == 'Laguerre': - geom = Geom.from_Laguerre_tessellation(grid,size,seeds,np.ones(2),periodic=np.random.random()>0.5) + grid = Grid.from_Laguerre_tessellation(cells,size,seeds,np.ones(2),periodic=np.random.random()>0.5) elif approach == 'Voronoi': - geom = Geom.from_Voronoi_tessellation(grid,size,seeds, periodic=np.random.random()>0.5) - assert np.all(geom.material == material) + grid = Grid.from_Voronoi_tessellation(cells,size,seeds, periodic=np.random.random()>0.5) + assert np.all(grid.material == material) @pytest.mark.parametrize('surface',['Schwarz P', @@ -363,14 +372,14 @@ class TestGeom: 'Fisher-Koch S', ]) def test_minimal_surface_basic_properties(self,surface): - grid = np.random.randint(60,100,3) - size = np.ones(3)+np.random.rand(3) + cells = np.random.randint(60,100,3) + size = np.ones(3)+np.random.rand(3) threshold = 2*np.random.rand()-1. periods = np.random.randint(2)+1 materials = np.random.randint(0,40,2) - geom = Geom.from_minimal_surface(grid,size,surface,threshold,periods,materials) - assert set(geom.material.flatten()) | set(materials) == set(materials) \ - and (geom.size == size).all() and (geom.grid == grid).all() + grid = Grid.from_minimal_surface(cells,size,surface,threshold,periods,materials) + assert set(grid.material.flatten()) | set(materials) == set(materials) \ + and (grid.size == size).all() and (grid.cells == cells).all() @pytest.mark.parametrize('surface,threshold',[('Schwarz P',0), ('Double Primitive',-1./6.), @@ -386,36 +395,36 @@ class TestGeom: ('Fisher-Koch S',0), ]) def test_minimal_surface_volume(self,surface,threshold): - grid = np.ones(3,dtype=int)*64 - geom = Geom.from_minimal_surface(grid,np.ones(3),surface,threshold) - assert np.isclose(np.count_nonzero(geom.material==1)/np.prod(geom.grid),.5,rtol=1e-3) + cells = np.ones(3,dtype=int)*64 + grid = Grid.from_minimal_surface(cells,np.ones(3),surface,threshold) + assert np.isclose(np.count_nonzero(grid.material==1)/np.prod(grid.cells),.5,rtol=1e-3) def test_from_table(self): - grid = np.random.randint(60,100,3) + cells = np.random.randint(60,100,3) size = np.ones(3)+np.random.rand(3) - coords = grid_filters.cell_coord0(grid,size).reshape(-1,3,order='F') - z=np.ones(grid.prod()) - z[grid[:2].prod()*int(grid[2]/2):]=0 + coords = grid_filters.coordinates0_point(cells,size).reshape(-1,3,order='F') + z=np.ones(cells.prod()) + z[cells[:2].prod()*int(cells[2]/2):]=0 t = Table(np.column_stack((coords,z)),{'coords':3,'z':1}) - g = Geom.from_table(t,'coords',['1_coords','z']) - assert g.N_materials == g.grid[0]*2 and (g.material[:,:,-1]-g.material[:,:,0] == grid[0]).all() + g = Grid.from_table(t,'coords',['1_coords','z']) + assert g.N_materials == g.cells[0]*2 and (g.material[:,:,-1]-g.material[:,:,0] == cells[0]).all() def test_from_table_recover(self,tmp_path): - grid = np.random.randint(60,100,3) + cells = np.random.randint(60,100,3) size = np.ones(3)+np.random.rand(3) s = seeds.from_random(size,np.random.randint(60,100)) - geom = Geom.from_Voronoi_tessellation(grid,size,s) - coords = grid_filters.cell_coord0(grid,size) - t = Table(np.column_stack((coords.reshape(-1,3,order='F'),geom.material.flatten(order='F'))),{'c':3,'m':1}) - assert geom_equal(geom.sort().renumber(),Geom.from_table(t,'c',['m'])) + grid = Grid.from_Voronoi_tessellation(cells,size,s) + coords = grid_filters.coordinates0_point(cells,size) + t = Table(np.column_stack((coords.reshape(-1,3,order='F'),grid.material.flatten(order='F'))),{'c':3,'m':1}) + assert grid_equal(grid.sort().renumber(),Grid.from_table(t,'c',['m'])) @pytest.mark.parametrize('periodic',[True,False]) @pytest.mark.parametrize('direction',['x','y','z',['x','y'],'zy','xz',['x','y','z']]) def test_get_grain_boundaries(self,update,ref_path,periodic,direction): - geom=Geom.load(ref_path/'get_grain_boundaries_8g12x15x20.vtr') - current=geom.get_grain_boundaries(periodic,direction) + grid=Grid.load(ref_path/'get_grain_boundaries_8g12x15x20.vtr') + current=grid.get_grain_boundaries(periodic,direction) if update: current.save(ref_path/f'get_grain_boundaries_8g12x15x20_{direction}_{periodic}.vtu',parallel=False) reference=VTK.load(ref_path/f'get_grain_boundaries_8g12x15x20_{"".join(direction)}_{periodic}.vtu') diff --git a/python/tests/test_Result.py b/python/tests/test_Result.py index 1e014216e..b8447b8b0 100644 --- a/python/tests/test_Result.py +++ b/python/tests/test_Result.py @@ -169,7 +169,7 @@ class TestResult: @pytest.mark.parametrize('d',[[1,0,0],[0,1,0],[0,0,1]]) def test_add_IPF_color(self,default,d): - default.add_IPF_color('O',np.array(d)) + default.add_IPF_color(d,'O') loc = {'O': default.get_dataset_location('O'), 'color': default.get_dataset_location('IPFcolor_[{} {} {}]'.format(*d))} qu = default.read_dataset(loc['O']).view(np.double).squeeze() @@ -356,11 +356,11 @@ class TestResult: @pytest.mark.parametrize('mode',['cell','node']) def test_coordinates(self,default,mode): if mode == 'cell': - a = grid_filters.cell_coord0(default.grid,default.size,default.origin) - b = default.cell_coordinates.reshape(tuple(default.grid)+(3,),order='F') + a = grid_filters.coordinates0_point(default.cells,default.size,default.origin) + b = default.coordinates0_point.reshape(tuple(default.cells)+(3,),order='F') elif mode == 'node': - a = grid_filters.node_coord0(default.grid,default.size,default.origin) - b = default.node_coordinates.reshape(tuple(default.grid+1)+(3,),order='F') + a = grid_filters.coordinates0_node(default.cells,default.size,default.origin) + b = default.coordinates0_node.reshape(tuple(default.cells+1)+(3,),order='F') assert np.allclose(a,b) @pytest.mark.parametrize('output',['F',[],['F','P']]) diff --git a/python/tests/test_Rotation.py b/python/tests/test_Rotation.py index a827b7a70..36e3a3ac9 100644 --- a/python/tests/test_Rotation.py +++ b/python/tests/test_Rotation.py @@ -800,6 +800,14 @@ class TestRotation: print(f'append 2x {shape} --> {s.shape}') assert s[0,...] == r[0,...] and s[-1,...] == p[-1,...] + @pytest.mark.parametrize('shape',[None,1,(1,),(4,2),(3,3,2)]) + def test_append_list(self,shape): + r = Rotation.from_random(shape=shape) + p = Rotation.from_random(shape=shape) + s = r.append([r,p]) + print(f'append 3x {shape} --> {s.shape}') + assert s[0,...] == r[0,...] and s[-1,...] == p[-1,...] + @pytest.mark.parametrize('quat,standardized',[ ([-1,0,0,0],[1,0,0,0]), ([-0.5,-0.5,-0.5,-0.5],[0.5,0.5,0.5,0.5]), @@ -1022,7 +1030,7 @@ class TestRotation: rng = tuple(zip(np.zeros(3),limits)) weights = Table.load(ref_path/'ODF_experimental_cell.txt').get('intensity').flatten() - Eulers = grid_filters.cell_coord0(steps,limits) + Eulers = grid_filters.coordinates0_point(steps,limits) Eulers = np.radians(Eulers) if not degrees else Eulers Eulers_r = Rotation.from_ODF(weights,Eulers.reshape(-1,3,order='F'),N,degrees,fractions).as_Euler_angles(True) @@ -1040,7 +1048,7 @@ class TestRotation: weights = Table.load(ref_path/'ODF_experimental.txt').get('intensity') weights = weights.reshape(steps+1,order='F')[:-1,:-1,:-1].reshape(-1,order='F') - Eulers = grid_filters.node_coord0(steps,limits)[:-1,:-1,:-1] + Eulers = grid_filters.coordinates0_node(steps,limits)[:-1,:-1,:-1] Eulers = np.radians(Eulers) if not degrees else Eulers Eulers_r = Rotation.from_ODF(weights,Eulers.reshape(-1,3,order='F'),N,degrees).as_Euler_angles(True) diff --git a/python/tests/test_Table.py b/python/tests/test_Table.py index b448e201d..8f617aff5 100644 --- a/python/tests/test_Table.py +++ b/python/tests/test_Table.py @@ -8,7 +8,7 @@ from damask import Table def default(): """Simple Table.""" x = np.ones((5,13),dtype=float) - return Table(x,{'F':(3,3),'v':(3,),'s':(1,)},['test data','contains only ones']) + return Table(x,{'F':(3,3),'v':(3,),'s':(1,)},['test data','contains five rows of only ones']) @pytest.fixture def ref_path(ref_path_base): @@ -20,8 +20,9 @@ class TestTable: def test_repr(self,default): print(default) - def test_len(self): - len(Table(np.random.rand(7,3),{'X':3})) == 7 + @pytest.mark.parametrize('N',[10,40]) + def test_len(self,N): + assert len(Table(np.random.rand(N,3),{'X':3})) == N def test_get_scalar(self,default): d = default.get('s') @@ -39,6 +40,10 @@ class TestTable: d = default.get('5_F') assert np.allclose(d,1.0) and d.shape[1:] == (1,) + @pytest.mark.parametrize('N',[10,40]) + def test_getitem(self,N): + assert len(Table(np.random.rand(N,1),{'X':1})[:N//2]) == N//2 + @pytest.mark.parametrize('mode',['str','path']) def test_write_read(self,default,tmp_path,mode): default.save(tmp_path/'default.txt') diff --git a/python/tests/test_VTK.py b/python/tests/test_VTK.py index 1b90fff88..a3cba354f 100644 --- a/python/tests/test_VTK.py +++ b/python/tests/test_VTK.py @@ -16,9 +16,9 @@ def ref_path(ref_path_base): @pytest.fixture def default(): """Simple VTK.""" - grid = np.array([5,6,7],int) - size = np.array([.6,1.,.5]) - return VTK.from_rectilinear_grid(grid,size) + cells = np.array([5,6,7],int) + size = np.array([.6,1.,.5]) + return VTK.from_rectilinear_grid(cells,size) class TestVTK: @@ -27,10 +27,10 @@ class TestVTK: print('patched damask.util.execution_stamp') def test_rectilinearGrid(self,tmp_path): - grid = np.random.randint(5,10,3)*2 + cells = np.random.randint(5,10,3)*2 size = np.random.random(3) + 1.0 origin = np.random.random(3) - v = VTK.from_rectilinear_grid(grid,size,origin) + v = VTK.from_rectilinear_grid(cells,size,origin) string = v.__repr__() v.save(tmp_path/'rectilinearGrid',False) vtr = VTK.load(tmp_path/'rectilinearGrid.vtr') @@ -152,11 +152,11 @@ class TestVTK: np.allclose(polyData.get('coordinates'),points) def test_compare_reference_rectilinearGrid(self,update,ref_path,tmp_path): - grid = np.array([5,6,7],int) - size = np.array([.6,1.,.5]) - rectilinearGrid = VTK.from_rectilinear_grid(grid,size) - c = grid_filters.cell_coord0(grid,size).reshape(-1,3,order='F') - n = grid_filters.node_coord0(grid,size).reshape(-1,3,order='F') + cells = np.array([5,6,7],int) + size = np.array([.6,1.,.5]) + rectilinearGrid = VTK.from_rectilinear_grid(cells,size) + c = grid_filters.coordinates0_point(cells,size).reshape(-1,3,order='F') + n = grid_filters.coordinates0_node(cells,size).reshape(-1,3,order='F') rectilinearGrid.add(c,'cell') rectilinearGrid.add(n,'node') if update: diff --git a/python/tests/test_grid_filters.py b/python/tests/test_grid_filters.py index 3acb554a7..d43e94c3c 100644 --- a/python/tests/test_grid_filters.py +++ b/python/tests/test_grid_filters.py @@ -5,124 +5,124 @@ from damask import grid_filters class TestGridFilters: - def test_cell_coord0(self): + def test_coordinates0_point(self): size = np.random.random(3) - grid = np.random.randint(8,32,(3)) - coord = grid_filters.cell_coord0(grid,size) - assert np.allclose(coord[0,0,0],size/grid*.5) and coord.shape == tuple(grid) + (3,) + cells = np.random.randint(8,32,(3)) + coord = grid_filters.coordinates0_point(cells,size) + assert np.allclose(coord[0,0,0],size/cells*.5) and coord.shape == tuple(cells) + (3,) - def test_node_coord0(self): + def test_coordinates0_node(self): size = np.random.random(3) - grid = np.random.randint(8,32,(3)) - coord = grid_filters.node_coord0(grid,size) - assert np.allclose(coord[-1,-1,-1],size) and coord.shape == tuple(grid+1) + (3,) + cells = np.random.randint(8,32,(3)) + coord = grid_filters.coordinates0_node(cells,size) + assert np.allclose(coord[-1,-1,-1],size) and coord.shape == tuple(cells+1) + (3,) def test_coord0(self): size = np.random.random(3) - grid = np.random.randint(8,32,(3)) - c = grid_filters.cell_coord0(grid+1,size+size/grid) - n = grid_filters.node_coord0(grid,size) + size/grid*.5 + cells = np.random.randint(8,32,(3)) + c = grid_filters.coordinates0_point(cells+1,size+size/cells) + n = grid_filters.coordinates0_node(cells,size) + size/cells*.5 assert np.allclose(c,n) - @pytest.mark.parametrize('mode',['cell','node']) + @pytest.mark.parametrize('mode',['point','node']) def test_grid_DNA(self,mode): - """Ensure that xx_coord0_gridSizeOrigin is the inverse of xx_coord0.""" - grid = np.random.randint(8,32,(3)) + """Ensure that cellsSizeOrigin_coordinates0_xx is the inverse of coordinates0_xx.""" + cells = np.random.randint(8,32,(3)) size = np.random.random(3) origin = np.random.random(3) - coord0 = eval(f'grid_filters.{mode}_coord0(grid,size,origin)') # noqa - _grid,_size,_origin = eval(f'grid_filters.{mode}_coord0_gridSizeOrigin(coord0.reshape(-1,3,order="F"))') - assert np.allclose(grid,_grid) and np.allclose(size,_size) and np.allclose(origin,_origin) + coord0 = eval(f'grid_filters.coordinates0_{mode}(cells,size,origin)') # noqa + _cells,_size,_origin = eval(f'grid_filters.cellsSizeOrigin_coordinates0_{mode}(coord0.reshape(-1,3,order="F"))') + assert np.allclose(cells,_cells) and np.allclose(size,_size) and np.allclose(origin,_origin) def test_displacement_fluct_equivalence(self): """Ensure that fluctuations are periodic.""" size = np.random.random(3) - grid = np.random.randint(8,32,(3)) - F = np.random.random(tuple(grid)+(3,3)) - assert np.allclose(grid_filters.node_displacement_fluct(size,F), - grid_filters.cell_2_node(grid_filters.cell_displacement_fluct(size,F))) + cells = np.random.randint(8,32,(3)) + F = np.random.random(tuple(cells)+(3,3)) + assert np.allclose(grid_filters.displacement_fluct_node(size,F), + grid_filters.point_to_node(grid_filters.displacement_fluct_point(size,F))) def test_interpolation_to_node(self): size = np.random.random(3) - grid = np.random.randint(8,32,(3)) - F = np.random.random(tuple(grid)+(3,3)) - assert np.allclose(grid_filters.node_coord(size,F) [1:-1,1:-1,1:-1], - grid_filters.cell_2_node(grid_filters.cell_coord(size,F))[1:-1,1:-1,1:-1]) + cells = np.random.randint(8,32,(3)) + F = np.random.random(tuple(cells)+(3,3)) + assert np.allclose(grid_filters.coordinates_node(size,F) [1:-1,1:-1,1:-1], + grid_filters.point_to_node(grid_filters.coordinates_point(size,F))[1:-1,1:-1,1:-1]) def test_interpolation_to_cell(self): - grid = np.random.randint(1,30,(3)) + cells = np.random.randint(1,30,(3)) - node_coord_x = np.linspace(0,np.pi*2,num=grid[0]+1) - node_field_x = np.cos(node_coord_x) - node_field = np.broadcast_to(node_field_x.reshape(-1,1,1),grid+1) + coordinates_node_x = np.linspace(0,np.pi*2,num=cells[0]+1) + node_field_x = np.cos(coordinates_node_x) + node_field = np.broadcast_to(node_field_x.reshape(-1,1,1),cells+1) - cell_coord_x = node_coord_x[:-1]+node_coord_x[1]*.5 - cell_field_x = np.interp(cell_coord_x,node_coord_x,node_field_x,period=np.pi*2.) - cell_field = np.broadcast_to(cell_field_x.reshape(-1,1,1),grid) + coordinates0_point_x = coordinates_node_x[:-1]+coordinates_node_x[1]*.5 + cell_field_x = np.interp(coordinates0_point_x,coordinates_node_x,node_field_x,period=np.pi*2.) + cell_field = np.broadcast_to(cell_field_x.reshape(-1,1,1),cells) - assert np.allclose(cell_field,grid_filters.node_2_cell(node_field)) + assert np.allclose(cell_field,grid_filters.node_2_point(node_field)) - @pytest.mark.parametrize('mode',['cell','node']) - def test_coord0_origin(self,mode): + @pytest.mark.parametrize('mode',['point','node']) + def test_coordinates0_origin(self,mode): origin= np.random.random(3) size = np.random.random(3) # noqa - grid = np.random.randint(8,32,(3)) - shifted = eval(f'grid_filters.{mode}_coord0(grid,size,origin)') - unshifted = eval(f'grid_filters.{mode}_coord0(grid,size)') + cells = np.random.randint(8,32,(3)) + shifted = eval(f'grid_filters.coordinates0_{mode}(cells,size,origin)') + unshifted = eval(f'grid_filters.coordinates0_{mode}(cells,size)') if mode == 'cell': - assert np.allclose(shifted,unshifted+np.broadcast_to(origin,tuple(grid) +(3,))) + assert np.allclose(shifted,unshifted+np.broadcast_to(origin,tuple(cells) +(3,))) elif mode == 'node': - assert np.allclose(shifted,unshifted+np.broadcast_to(origin,tuple(grid+1)+(3,))) + assert np.allclose(shifted,unshifted+np.broadcast_to(origin,tuple(cells+1)+(3,))) - @pytest.mark.parametrize('function',[grid_filters.cell_displacement_avg, - grid_filters.node_displacement_avg]) + @pytest.mark.parametrize('function',[grid_filters.displacement_avg_point, + grid_filters.displacement_avg_node]) def test_displacement_avg_vanishes(self,function): """Ensure that random fluctuations in F do not result in average displacement.""" size = np.random.random(3) - grid = np.random.randint(8,32,(3)) - F = np.random.random(tuple(grid)+(3,3)) + cells = np.random.randint(8,32,(3)) + F = np.random.random(tuple(cells)+(3,3)) F += np.eye(3) - np.average(F,axis=(0,1,2)) assert np.allclose(function(size,F),0.0) - @pytest.mark.parametrize('function',[grid_filters.cell_displacement_fluct, - grid_filters.node_displacement_fluct]) + @pytest.mark.parametrize('function',[grid_filters.displacement_fluct_point, + grid_filters.displacement_fluct_node]) def test_displacement_fluct_vanishes(self,function): """Ensure that constant F does not result in fluctuating displacement.""" size = np.random.random(3) - grid = np.random.randint(8,32,(3)) - F = np.broadcast_to(np.random.random((3,3)), tuple(grid)+(3,3)) + cells = np.random.randint(8,32,(3)) + F = np.broadcast_to(np.random.random((3,3)), tuple(cells)+(3,3)) assert np.allclose(function(size,F),0.0) - @pytest.mark.parametrize('function',[grid_filters.coord0_check, - grid_filters.node_coord0_gridSizeOrigin, - grid_filters.cell_coord0_gridSizeOrigin]) + @pytest.mark.parametrize('function',[grid_filters.coordinates0_check, + grid_filters.cellsSizeOrigin_coordinates0_node, + grid_filters.cellsSizeOrigin_coordinates0_point]) def test_invalid_coordinates(self,function): invalid_coordinates = np.random.random((np.random.randint(12,52),3)) with pytest.raises(ValueError): function(invalid_coordinates) - @pytest.mark.parametrize('function',[grid_filters.node_coord0_gridSizeOrigin, - grid_filters.cell_coord0_gridSizeOrigin]) + @pytest.mark.parametrize('function',[grid_filters.cellsSizeOrigin_coordinates0_node, + grid_filters.cellsSizeOrigin_coordinates0_point]) def test_uneven_spaced_coordinates(self,function): start = np.random.random(3) end = np.random.random(3)*10. + start - grid = np.random.randint(8,32,(3)) - uneven = np.stack(np.meshgrid(np.logspace(start[0],end[0],grid[0]), - np.logspace(start[1],end[1],grid[1]), - np.logspace(start[2],end[2],grid[2]),indexing = 'ij'), - axis = -1).reshape((grid.prod(),3),order='F') + cells = np.random.randint(8,32,(3)) + uneven = np.stack(np.meshgrid(np.logspace(start[0],end[0],cells[0]), + np.logspace(start[1],end[1],cells[1]), + np.logspace(start[2],end[2],cells[2]),indexing = 'ij'), + axis = -1).reshape((cells.prod(),3),order='F') with pytest.raises(ValueError): function(uneven) @pytest.mark.parametrize('mode',[True,False]) - @pytest.mark.parametrize('function',[grid_filters.node_coord0_gridSizeOrigin, - grid_filters.cell_coord0_gridSizeOrigin]) + @pytest.mark.parametrize('function',[grid_filters.cellsSizeOrigin_coordinates0_node, + grid_filters.cellsSizeOrigin_coordinates0_point]) def test_unordered_coordinates(self,function,mode): origin = np.random.random(3) size = np.random.random(3)*10.+origin - grid = np.random.randint(8,32,(3)) - unordered = grid_filters.node_coord0(grid,size,origin).reshape(-1,3) + cells = np.random.randint(8,32,(3)) + unordered = grid_filters.coordinates0_node(cells,size,origin).reshape(-1,3) if mode: with pytest.raises(ValueError): function(unordered,mode) @@ -131,9 +131,9 @@ class TestGridFilters: def test_regrid(self): size = np.random.random(3) - grid = np.random.randint(8,32,(3)) - F = np.broadcast_to(np.eye(3), tuple(grid)+(3,3)) - assert all(grid_filters.regrid(size,F,grid) == np.arange(grid.prod())) + cells = np.random.randint(8,32,(3)) + F = np.broadcast_to(np.eye(3), tuple(cells)+(3,3)) + assert all(grid_filters.regrid(size,F,cells) == np.arange(cells.prod())) @pytest.mark.parametrize('differential_operator',[grid_filters.curl, @@ -141,14 +141,14 @@ class TestGridFilters: grid_filters.gradient]) def test_differential_operator_constant(self,differential_operator): size = np.random.random(3)+1.0 - grid = np.random.randint(8,32,(3)) + cells = np.random.randint(8,32,(3)) shapes = { grid_filters.curl: [(3,),(3,3)], grid_filters.divergence:[(3,),(3,3)], grid_filters.gradient: [(1,),(3,)] } for shape in shapes[differential_operator]: - field = np.ones(tuple(grid)+shape)*np.random.random()*1.0e5 + field = np.ones(tuple(cells)+shape)*np.random.random()*1.0e5 assert np.allclose(differential_operator(size,field),0.0) @@ -190,15 +190,15 @@ class TestGridFilters: @pytest.mark.parametrize('field_def,grad_def',grad_test_data) def test_grad(self,field_def,grad_def): size = np.random.random(3)+1.0 - grid = np.random.randint(8,32,(3)) + cells = np.random.randint(8,32,(3)) - nodes = grid_filters.cell_coord0(grid,size) + nodes = grid_filters.coordinates0_point(cells,size) my_locals = locals() # needed for list comprehension - field = np.stack([np.broadcast_to(eval(f,globals(),my_locals),grid) for f in field_def],axis=-1) - field = field.reshape(tuple(grid) + ((3,) if len(field_def)==3 else (1,))) - grad = np.stack([np.broadcast_to(eval(c,globals(),my_locals),grid) for c in grad_def], axis=-1) - grad = grad.reshape(tuple(grid) + ((3,3) if len(grad_def)==9 else (3,))) + field = np.stack([np.broadcast_to(eval(f,globals(),my_locals),cells) for f in field_def],axis=-1) + field = field.reshape(tuple(cells) + ((3,) if len(field_def)==3 else (1,))) + grad = np.stack([np.broadcast_to(eval(c,globals(),my_locals),cells) for c in grad_def], axis=-1) + grad = grad.reshape(tuple(cells) + ((3,3) if len(grad_def)==9 else (3,))) assert np.allclose(grad,grid_filters.gradient(size,field)) @@ -250,15 +250,15 @@ class TestGridFilters: @pytest.mark.parametrize('field_def,curl_def',curl_test_data) def test_curl(self,field_def,curl_def): size = np.random.random(3)+1.0 - grid = np.random.randint(8,32,(3)) + cells = np.random.randint(8,32,(3)) - nodes = grid_filters.cell_coord0(grid,size) + nodes = grid_filters.coordinates0_point(cells,size) my_locals = locals() # needed for list comprehension - field = np.stack([np.broadcast_to(eval(f,globals(),my_locals),grid) for f in field_def],axis=-1) - field = field.reshape(tuple(grid) + ((3,3) if len(field_def)==9 else (3,))) - curl = np.stack([np.broadcast_to(eval(c,globals(),my_locals),grid) for c in curl_def], axis=-1) - curl = curl.reshape(tuple(grid) + ((3,3) if len(curl_def)==9 else (3,))) + field = np.stack([np.broadcast_to(eval(f,globals(),my_locals),cells) for f in field_def],axis=-1) + field = field.reshape(tuple(cells) + ((3,3) if len(field_def)==9 else (3,))) + curl = np.stack([np.broadcast_to(eval(c,globals(),my_locals),cells) for c in curl_def], axis=-1) + curl = curl.reshape(tuple(cells) + ((3,3) if len(curl_def)==9 else (3,))) assert np.allclose(curl,grid_filters.curl(size,field)) @@ -303,17 +303,17 @@ class TestGridFilters: def test_div(self,field_def,div_def): size = np.random.random(3)+1.0 - grid = np.random.randint(8,32,(3)) + cells = np.random.randint(8,32,(3)) - nodes = grid_filters.cell_coord0(grid,size) + nodes = grid_filters.coordinates0_point(cells,size) my_locals = locals() # needed for list comprehension - field = np.stack([np.broadcast_to(eval(f,globals(),my_locals),grid) for f in field_def],axis=-1) - field = field.reshape(tuple(grid) + ((3,3) if len(field_def)==9 else (3,))) - div = np.stack([np.broadcast_to(eval(c,globals(),my_locals),grid) for c in div_def], axis=-1) + field = np.stack([np.broadcast_to(eval(f,globals(),my_locals),cells) for f in field_def],axis=-1) + field = field.reshape(tuple(cells) + ((3,3) if len(field_def)==9 else (3,))) + div = np.stack([np.broadcast_to(eval(c,globals(),my_locals),cells) for c in div_def], axis=-1) if len(div_def)==3: - div = div.reshape(tuple(grid) + ((3,))) + div = div.reshape(tuple(cells) + ((3,))) else: - div=div.reshape(tuple(grid)) + div=div.reshape(tuple(cells)) assert np.allclose(div,grid_filters.divergence(size,field)) diff --git a/python/tests/test_seeds.py b/python/tests/test_seeds.py index c9ad6f0e3..af27e74af 100644 --- a/python/tests/test_seeds.py +++ b/python/tests/test_seeds.py @@ -4,15 +4,15 @@ from scipy.spatial import cKDTree from damask import seeds from damask import grid_filters -from damask import Geom +from damask import Grid class TestSeeds: - @pytest.mark.parametrize('grid',[None,np.ones(3,dtype='i')*10]) - def test_from_random(self,grid): + @pytest.mark.parametrize('cells',[None,np.ones(3,dtype='i')*10]) + def test_from_random(self,cells): N_seeds = np.random.randint(30,300) size = np.ones(3) + np.random.random(3) - coords = seeds.from_random(size,N_seeds,grid) + coords = seeds.from_random(size,N_seeds,cells) assert (0<=coords).all() and (coords=distance - def test_from_geom_reconstruct(self): - grid = np.random.randint(10,20,3) + def test_from_grid_reconstruct(self): + cells = np.random.randint(10,20,3) N_seeds = np.random.randint(30,300) size = np.ones(3) + np.random.random(3) - coords = seeds.from_random(size,N_seeds,grid) - geom_1 = Geom.from_Voronoi_tessellation(grid,size,coords) - coords,material = seeds.from_geom(geom_1) - geom_2 = Geom.from_Voronoi_tessellation(grid,size,coords,material) - assert (geom_2.material==geom_1.material).all() + coords = seeds.from_random(size,N_seeds,cells) + grid_1 = Grid.from_Voronoi_tessellation(cells,size,coords) + coords,material = seeds.from_grid(grid_1) + grid_2 = Grid.from_Voronoi_tessellation(cells,size,coords,material) + assert (grid_2.material==grid_1.material).all() @pytest.mark.parametrize('periodic',[True,False]) @pytest.mark.parametrize('average',[True,False]) - def test_from_geom_grid(self,periodic,average): - grid = np.random.randint(10,20,3) - size = np.ones(3) + np.random.random(3) - coords = grid_filters.cell_coord0(grid,size).reshape(-1,3) + def test_from_grid_grid(self,periodic,average): + cells = np.random.randint(10,20,3) + size = np.ones(3) + np.random.random(3) + coords = grid_filters.coordinates0_point(cells,size).reshape(-1,3) np.random.shuffle(coords) - geom_1 = Geom.from_Voronoi_tessellation(grid,size,coords) - coords,material = seeds.from_geom(geom_1,average=average,periodic=periodic) - geom_2 = Geom.from_Voronoi_tessellation(grid,size,coords,material) - assert (geom_2.material==geom_1.material).all() + grid_1 = Grid.from_Voronoi_tessellation(cells,size,coords) + coords,material = seeds.from_grid(grid_1,average=average,periodic=periodic) + grid_2 = Grid.from_Voronoi_tessellation(cells,size,coords,material) + assert (grid_2.material==grid_1.material).all() @pytest.mark.parametrize('periodic',[True,False]) @pytest.mark.parametrize('average',[True,False]) @pytest.mark.parametrize('invert',[True,False]) - def test_from_geom_selection(self,periodic,average,invert): - grid = np.random.randint(10,20,3) + def test_from_grid_selection(self,periodic,average,invert): + cells = np.random.randint(10,20,3) N_seeds = np.random.randint(30,300) size = np.ones(3) + np.random.random(3) - coords = seeds.from_random(size,N_seeds,grid) - geom = Geom.from_Voronoi_tessellation(grid,size,coords) + coords = seeds.from_random(size,N_seeds,cells) + grid = Grid.from_Voronoi_tessellation(cells,size,coords) selection=np.random.randint(N_seeds)+1 - coords,material = seeds.from_geom(geom,average=average,periodic=periodic,invert=invert,selection=[selection]) + coords,material = seeds.from_grid(grid,average=average,periodic=periodic,invert=invert,selection=[selection]) assert selection not in material if invert else (selection==material).all() diff --git a/src/CPFEM.f90 b/src/CPFEM.f90 index c49ecbcb6..240688a8c 100644 --- a/src/CPFEM.f90 +++ b/src/CPFEM.f90 @@ -5,7 +5,6 @@ !-------------------------------------------------------------------------------------------------- module CPFEM use prec - use FEsolving use math use rotations use YAML_types @@ -13,7 +12,6 @@ module CPFEM use discretization_marc use material use config - use crystallite use homogenization use IO use discretization @@ -89,8 +87,8 @@ subroutine CPFEM_initAll call lattice_init call material_init(.false.) call constitutive_init - call crystallite_init call homogenization_init + call crystallite_init call CPFEM_init call config_deallocate @@ -153,7 +151,7 @@ subroutine CPFEM_general(mode, ffn, ffn1, temperature_inp, dt, elFE, ip, cauchyS H integer(pInt) elCP, & ! crystal plasticity element number - i, j, k, l, m, n, ph, homog, mySource + i, j, k, l, m, n, ph, homog, mySource,ma real(pReal), parameter :: ODD_STRESS = 1e15_pReal, & !< return value for stress if terminallyIll ODD_JACOBIAN = 1e50_pReal !< return value for jacobian if terminallyIll @@ -161,6 +159,8 @@ subroutine CPFEM_general(mode, ffn, ffn1, temperature_inp, dt, elFE, ip, cauchyS elCP = mesh_FEM2DAMASK_elem(elFE) + ma = (elCP-1) * discretization_nIPs + ip + if (debugCPFEM%basic .and. elCP == debugCPFEM%element .and. ip == debugCPFEM%ip) then print'(/,a)', '#############################################' print'(a1,a22,1x,i8,a13)', '#','element', elCP, '#' @@ -181,11 +181,11 @@ subroutine CPFEM_general(mode, ffn, ffn1, temperature_inp, dt, elFE, ip, cauchyS chosenThermal1: select case (thermal_type(material_homogenizationAt(elCP))) case (THERMAL_conduction_ID) chosenThermal1 - temperature(material_homogenizationAt(elCP))%p(thermalMapping(material_homogenizationAt(elCP))%p(ip,elCP)) = & + temperature(material_homogenizationAt(elCP))%p(material_homogenizationMemberAt(ip,elCP)) = & temperature_inp end select chosenThermal1 - homogenization_F0(1:3,1:3,ip,elCP) = ffn - homogenization_F(1:3,1:3,ip,elCP) = ffn1 + homogenization_F0(1:3,1:3,ma) = ffn + homogenization_F(1:3,1:3,ma) = ffn1 if (iand(mode, CPFEM_CALCRESULTS) /= 0_pInt) then @@ -196,11 +196,9 @@ subroutine CPFEM_general(mode, ffn, ffn1, temperature_inp, dt, elFE, ip, cauchyS CPFEM_dcsde(1:6,1:6,ip,elCP) = ODD_JACOBIAN * math_eye(6) else validCalculation - FEsolving_execElem = elCP - FEsolving_execIP = ip if (debugCPFEM%extensive) & print'(a,i8,1x,i2)', '<< CPFEM >> calculation for elFE ip ',elFE,ip - call materialpoint_stressAndItsTangent(dt) + call materialpoint_stressAndItsTangent(dt,[ip,ip],[elCP,elCP]) terminalIllness: if (terminallyIll) then @@ -212,17 +210,17 @@ subroutine CPFEM_general(mode, ffn, ffn1, temperature_inp, dt, elFE, ip, cauchyS else terminalIllness ! translate from P to sigma - Kirchhoff = matmul(homogenization_P(1:3,1:3,ip,elCP), transpose(homogenization_F(1:3,1:3,ip,elCP))) - J_inverse = 1.0_pReal / math_det33(homogenization_F(1:3,1:3,ip,elCP)) + Kirchhoff = matmul(homogenization_P(1:3,1:3,ma), transpose(homogenization_F(1:3,1:3,ma))) + J_inverse = 1.0_pReal / math_det33(homogenization_F(1:3,1:3,ma)) CPFEM_cs(1:6,ip,elCP) = math_sym33to6(J_inverse * Kirchhoff,weighted=.false.) ! translate from dP/dF to dCS/dE H = 0.0_pReal do i=1,3; do j=1,3; do k=1,3; do l=1,3; do m=1,3; do n=1,3 H(i,j,k,l) = H(i,j,k,l) & - + homogenization_F(j,m,ip,elCP) * homogenization_F(l,n,ip,elCP) & - * homogenization_dPdF(i,m,k,n,ip,elCP) & - - math_delta(j,l) * homogenization_F(i,m,ip,elCP) * homogenization_P(k,m,ip,elCP) & + + homogenization_F(j,m,ma) * homogenization_F(l,n,ma) & + * homogenization_dPdF(i,m,k,n,ma) & + - math_delta(j,l) * homogenization_F(i,m,ma) * homogenization_P(k,m,ma) & + 0.5_pReal * ( Kirchhoff(j,l)*math_delta(i,k) + Kirchhoff(i,k)*math_delta(j,l) & + Kirchhoff(j,k)*math_delta(i,l) + Kirchhoff(i,l)*math_delta(j,k)) enddo; enddo; enddo; enddo; enddo; enddo @@ -259,7 +257,8 @@ end subroutine CPFEM_general !-------------------------------------------------------------------------------------------------- subroutine CPFEM_forward - call crystallite_forward + call homogenization_forward + call constitutive_forward end subroutine CPFEM_forward @@ -275,7 +274,6 @@ subroutine CPFEM_results(inc,time) call results_openJobFile call results_addIncrement(inc,time) call constitutive_results - call crystallite_results call homogenization_results call discretization_results call results_finalizeIncrement diff --git a/src/CPFEM2.f90 b/src/CPFEM2.f90 index 994859758..5a500875d 100644 --- a/src/CPFEM2.f90 +++ b/src/CPFEM2.f90 @@ -6,7 +6,6 @@ module CPFEM2 use prec use config - use FEsolving use math use rotations use YAML_types @@ -21,7 +20,6 @@ module CPFEM2 use HDF5_utilities use homogenization use constitutive - use crystallite #if defined(Mesh) use FEM_quadrature use discretization_mesh @@ -63,8 +61,8 @@ subroutine CPFEM_initAll #endif call material_init(restart=interface_restartInc>0) call constitutive_init - call crystallite_init call homogenization_init + call crystallite_init call CPFEM_init call config_deallocate @@ -98,7 +96,8 @@ end subroutine CPFEM_restartWrite !-------------------------------------------------------------------------------------------------- subroutine CPFEM_forward - call crystallite_forward + call homogenization_forward + call constitutive_forward end subroutine CPFEM_forward @@ -114,7 +113,6 @@ subroutine CPFEM_results(inc,time) call results_openJobFile call results_addIncrement(inc,time) call constitutive_results - call crystallite_results call homogenization_results call discretization_results call results_finalizeIncrement diff --git a/src/DAMASK_interface.f90 b/src/DAMASK_interface.f90 index 41f421eb8..c43e354a2 100644 --- a/src/DAMASK_interface.f90 +++ b/src/DAMASK_interface.f90 @@ -10,7 +10,7 @@ !> and working directory. !-------------------------------------------------------------------------------------------------- #define PETSC_MAJOR 3 -#define PETSC_MINOR_MIN 10 +#define PETSC_MINOR_MIN 12 #define PETSC_MINOR_MAX 14 module DAMASK_interface @@ -54,12 +54,6 @@ subroutine DAMASK_interface_init =================================================================================================== -- WRONG PETSc VERSION --- WRONG PETSc VERSION --- WRONG PETSc VERSION --- WRONG PETSc VERSION -- =================================================================================================== -============ THIS VERSION OF DAMASK REQUIRES A DIFFERENT PETSc VERSION ======================== -=============== THIS VERSION OF DAMASK REQUIRES A DIFFERENT PETSc VERSION ===================== -================== THIS VERSION OF DAMASK REQUIRES A DIFFERENT PETSc VERSION ================== -=================================================================================================== --- WRONG PETSc VERSION --- WRONG PETSc VERSION --- WRONG PETSc VERSION --- WRONG PETSc VERSION -- -=================================================================================================== #endif character(len=pPathLen*3+pStringLen) :: & @@ -392,7 +386,7 @@ end function makeRelativePath subroutine catchSIGTERM(signal) bind(C) integer(C_INT), value :: signal - interface_SIGTERM = .true. + call interface_setSIGTERM(.true.) print'(a,i0,a)', ' received signal ',signal, ', set SIGTERM=TRUE' @@ -417,7 +411,7 @@ end subroutine interface_setSIGTERM subroutine catchSIGUSR1(signal) bind(C) integer(C_INT), value :: signal - interface_SIGUSR1 = .true. + call interface_setSIGUSR1(.true.) print'(a,i0,a)', ' received signal ',signal, ', set SIGUSR1=TRUE' @@ -442,7 +436,7 @@ end subroutine interface_setSIGUSR1 subroutine catchSIGUSR2(signal) bind(C) integer(C_INT), value :: signal - interface_SIGUSR2 = .true. + call interface_setSIGUSR2(.true.) print'(a,i0,a)', ' received signal ',signal, ', set SIGUSR2=TRUE' diff --git a/src/DAMASK_marc.f90 b/src/DAMASK_marc.f90 index ea7430c6b..0ad68445c 100644 --- a/src/DAMASK_marc.f90 +++ b/src/DAMASK_marc.f90 @@ -176,7 +176,6 @@ subroutine hypela2(d,g,e,de,s,t,dt,ngens,m,nn,kcus,matus,ndi,nshear,disp, & use DAMASK_interface use config use YAML_types - use FEsolving use discretization_marc use homogenization use CPFEM diff --git a/src/FEsolving.f90 b/src/FEsolving.f90 deleted file mode 100644 index 3fc1482d3..000000000 --- a/src/FEsolving.f90 +++ /dev/null @@ -1,15 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -!> @author Franz Roters, Max-Planck-Institut für Eisenforschung GmbH -!> @author Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH -!> @brief global variables for flow control -!-------------------------------------------------------------------------------------------------- -module FEsolving - - implicit none - public - - integer, dimension(2) :: & - FEsolving_execElem, & !< for ping-pong scheme always whole range, otherwise one specific element - FEsolving_execIP !< for ping-pong scheme always range to max IP, otherwise one specific IP - -end module FEsolving diff --git a/src/HDF5_utilities.f90 b/src/HDF5_utilities.f90 index 47f4243e7..88b8d960d 100644 --- a/src/HDF5_utilities.f90 +++ b/src/HDF5_utilities.f90 @@ -12,7 +12,6 @@ module HDF5_utilities use prec use parallelization - use rotations implicit none public @@ -37,7 +36,6 @@ module HDF5_utilities module procedure HDF5_read_int5 module procedure HDF5_read_int6 module procedure HDF5_read_int7 - end interface HDF5_read !-------------------------------------------------------------------------------------------------- @@ -60,9 +58,6 @@ module HDF5_utilities module procedure HDF5_write_int5 module procedure HDF5_write_int6 module procedure HDF5_write_int7 - - module procedure HDF5_write_rotation - end interface HDF5_write !-------------------------------------------------------------------------------------------------- @@ -175,7 +170,7 @@ end subroutine HDF5_closeFile !-------------------------------------------------------------------------------------------------- integer(HID_T) function HDF5_addGroup(fileHandle,groupName) - integer(HID_T), intent(in) :: fileHandle + integer(HID_T), intent(in) :: fileHandle character(len=*), intent(in) :: groupName integer :: hdferr @@ -1663,82 +1658,6 @@ subroutine HDF5_write_int7(loc_id,dataset,datasetName,parallel) end subroutine HDF5_write_int7 -!-------------------------------------------------------------------------------------------------- -!> @brief writes a scalar orientation dataset -! ToDo: It might be possible to write the dataset as a whole -! ToDo: We could optionally write out other representations (axis angle, euler, ...) -!-------------------------------------------------------------------------------------------------- -subroutine HDF5_write_rotation(loc_id,dataset,datasetName,parallel) - - type(rotation), intent(in), dimension(:) :: dataset !< data written to file - integer(HID_T), intent(in) :: loc_id !< file or group handle - character(len=*), intent(in) :: datasetName !< name of the dataset in the file - logical, intent(in), optional :: parallel - - integer :: hdferr - real(pReal), dimension(4,size(dataset)) :: dataset_asArray - integer(HID_T) :: dset_id, filespace_id, memspace_id, plist_id,dtype_id,w_id,x_id,y_id,z_id - integer(HSIZE_T), dimension(size(shape(dataset))) :: & - myStart, & - myShape, & !< shape of the dataset (this process) - totalShape !< shape of the dataset (all processes) - integer(SIZE_T) :: type_size_real - integer :: i - - do i = 1, size(dataset) - dataset_asArray(1:4,i) = dataset(i)%asQuaternion() - enddo - -!--------------------------------------------------------------------------------------------------- -! determine shape of dataset - myShape = int(shape(dataset),HSIZE_T) - -!--------------------------------------------------------------------------------------------------- -! compound type: name of each quaternion component - call h5tget_size_f(H5T_NATIVE_DOUBLE, type_size_real, hdferr) - - call h5tcreate_f(H5T_COMPOUND_F, type_size_real*4_SIZE_T, dtype_id, hdferr) - call h5tinsert_f(dtype_id, "w", type_size_real*0_SIZE_T, H5T_NATIVE_DOUBLE, hdferr) - call h5tinsert_f(dtype_id, "x", type_size_real*1_SIZE_T, H5T_NATIVE_DOUBLE, hdferr) - call h5tinsert_f(dtype_id, "y", type_size_real*2_SIZE_T, H5T_NATIVE_DOUBLE, hdferr) - call h5tinsert_f(dtype_id, "z", type_size_real*3_SIZE_T, H5T_NATIVE_DOUBLE, hdferr) - - if (present(parallel)) then - call initialize_write(dset_id, filespace_id, memspace_id, plist_id, & - myStart, totalShape, loc_id,myShape,datasetName,dtype_id,parallel) - else - call initialize_write(dset_id, filespace_id, memspace_id, plist_id, & - myStart, totalShape, loc_id,myShape,datasetName,dtype_id,.false.) - endif - - call h5pset_preserve_f(plist_id, .TRUE., hdferr) - - if (product(totalShape) /= 0) then - call h5tcreate_f(H5T_COMPOUND_F, type_size_real, x_id, hdferr) - call h5tinsert_f(x_id, "x", 0_SIZE_T, H5T_NATIVE_DOUBLE, hdferr) - call h5tcreate_f(H5T_COMPOUND_F, type_size_real, w_id, hdferr) - call h5tinsert_f(w_id, "w", 0_SIZE_T, H5T_NATIVE_DOUBLE, hdferr) - call h5tcreate_f(H5T_COMPOUND_F, type_size_real, y_id, hdferr) - call h5tinsert_f(y_id, "y", 0_SIZE_T, H5T_NATIVE_DOUBLE, hdferr) - call h5tcreate_f(H5T_COMPOUND_F, type_size_real, z_id, hdferr) - call h5tinsert_f(z_id, "z", 0_SIZE_T, H5T_NATIVE_DOUBLE, hdferr) - - call h5dwrite_f(dset_id, w_id,dataset_asArray(1,:),int(totalShape,HSIZE_T), hdferr,& - file_space_id = filespace_id, mem_space_id = memspace_id, xfer_prp = plist_id) - call h5dwrite_f(dset_id, x_id,dataset_asArray(2,:),int(totalShape,HSIZE_T), hdferr,& - file_space_id = filespace_id, mem_space_id = memspace_id, xfer_prp = plist_id) - call h5dwrite_f(dset_id, y_id,dataset_asArray(3,:),int(totalShape,HSIZE_T), hdferr,& - file_space_id = filespace_id, mem_space_id = memspace_id, xfer_prp = plist_id) - call h5dwrite_f(dset_id, z_id,dataset_asArray(4,:),int(totalShape,HSIZE_T), hdferr,& - file_space_id = filespace_id, mem_space_id = memspace_id, xfer_prp = plist_id) - if(hdferr < 0) error stop 'HDF5 error' - endif - - call finalize_write(plist_id, dset_id, filespace_id, memspace_id) - -end subroutine HDF5_write_rotation - - !-------------------------------------------------------------------------------------------------- !> @brief initialize HDF5 handles, determines global shape and start for parallel read !-------------------------------------------------------------------------------------------------- @@ -1789,7 +1708,7 @@ subroutine initialize_read(dset_id, filespace_id, memspace_id, plist_id, aplist_ !-------------------------------------------------------------------------------------------------- ! creating a property list for IO and set it to collective call h5pcreate_f(H5P_DATASET_ACCESS_F, aplist_id, hdferr) - if(hdferr < 0) error stop 'HDF5 error' + if(hdferr < 0) error stop 'HDF5 error' #ifdef PETSc call h5pset_all_coll_metadata_ops_f(aplist_id, .true., hdferr) if(hdferr < 0) error stop 'HDF5 error' @@ -1815,7 +1734,7 @@ end subroutine initialize_read !-------------------------------------------------------------------------------------------------- subroutine finalize_read(dset_id, filespace_id, memspace_id, plist_id, aplist_id) - integer(HID_T), intent(in) :: dset_id, filespace_id, memspace_id, plist_id, aplist_id + integer(HID_T), intent(in) :: dset_id, filespace_id, memspace_id, plist_id, aplist_id integer :: hdferr call h5pclose_f(plist_id, hdferr) @@ -1836,8 +1755,8 @@ end subroutine finalize_read !> @brief initialize HDF5 handles, determines global shape and start for parallel write !-------------------------------------------------------------------------------------------------- subroutine initialize_write(dset_id, filespace_id, memspace_id, plist_id, & - myStart, totalShape, & - loc_id,myShape,datasetName,datatype,parallel) + myStart, totalShape, & + loc_id,myShape,datasetName,datatype,parallel) integer(HID_T), intent(in) :: loc_id !< file or group handle character(len=*), intent(in) :: datasetName !< name of the dataset in the file @@ -1850,10 +1769,10 @@ subroutine initialize_write(dset_id, filespace_id, memspace_id, plist_id, & totalShape !< shape of the dataset (all processes) integer(HID_T), intent(out) :: dset_id, filespace_id, memspace_id, plist_id - integer, dimension(worldsize) :: & - writeSize !< contribution of all processes - integer :: ierr - integer :: hdferr + integer, dimension(worldsize) :: writeSize !< contribution of all processes + integer(HID_T) :: dcpl + integer :: ierr, hdferr + integer(HSIZE_T), parameter :: chunkSize = 1024_HSIZE_T**2/8_HSIZE_T !------------------------------------------------------------------------------------------------- ! creating a property list for transfer properties (is collective when reading in parallel) @@ -1880,6 +1799,21 @@ subroutine initialize_write(dset_id, filespace_id, memspace_id, plist_id, & myStart(ubound(myStart)) = int(sum(writeSize(1:worldrank)),HSIZE_T) totalShape = [myShape(1:ubound(myShape,1)-1),int(sum(writeSize),HSIZE_T)] +!-------------------------------------------------------------------------------------------------- +! compress (and chunk) larger datasets + call h5pcreate_f(H5P_DATASET_CREATE_F, dcpl, hdferr) + if(hdferr < 0) error stop 'HDF5 error' + if(product(totalShape) >= chunkSize*2_HSIZE_T) then + call h5pset_chunk_f(dcpl, size(totalShape), getChunks(totalShape,chunkSize), hdferr) + if(hdferr < 0) error stop 'HDF5 error' + call h5pset_shuffle_f(dcpl, hdferr) + if(hdferr < 0) error stop 'HDF5 error' + call h5pset_deflate_f(dcpl, 6, hdferr) + if(hdferr < 0) error stop 'HDF5 error' + call h5pset_Fletcher32_f(dcpl,hdferr) + if(hdferr < 0) error stop 'HDF5 error' + endif + !-------------------------------------------------------------------------------------------------- ! create dataspace in memory (local shape) and in file (global shape) call h5screate_simple_f(size(myShape), myShape, memspace_id, hdferr, myShape) @@ -1889,11 +1823,29 @@ subroutine initialize_write(dset_id, filespace_id, memspace_id, plist_id, & !-------------------------------------------------------------------------------------------------- ! create dataset in the file and select a hyperslab from it (the portion of the current process) - call h5dcreate_f(loc_id, trim(datasetName), datatype, filespace_id, dset_id, hdferr) + call h5dcreate_f(loc_id, trim(datasetName), datatype, filespace_id, dset_id, hdferr, dcpl) if(hdferr < 0) error stop 'HDF5 error' call h5sselect_hyperslab_f(filespace_id, H5S_SELECT_SET_F, myStart, myShape, hdferr) if(hdferr < 0) error stop 'HDF5 error' + call h5pclose_f(dcpl , hdferr) + if(hdferr < 0) error stop 'HDF5 error' + + contains + !------------------------------------------------------------------------------------------------ + !> @brief determine chunk layout + !------------------------------------------------------------------------------------------------ + pure function getChunks(totalShape,chunkSize) + + integer(HSIZE_T), dimension(:), intent(in) :: totalShape + integer(HSIZE_T), intent(in) :: chunkSize + integer(HSIZE_T), dimension(size(totalShape)) :: getChunks + + getChunks = [totalShape(1:size(totalShape)-1),& + chunkSize/product(totalShape(1:size(totalShape)-1))] + + end function getChunks + end subroutine initialize_write @@ -1916,4 +1868,5 @@ subroutine finalize_write(plist_id, dset_id, filespace_id, memspace_id) end subroutine finalize_write + end module HDF5_Utilities diff --git a/src/commercialFEM_fileList.f90 b/src/commercialFEM_fileList.f90 index d161b36eb..674ec4c43 100644 --- a/src/commercialFEM_fileList.f90 +++ b/src/commercialFEM_fileList.f90 @@ -11,9 +11,7 @@ #include "config.f90" #include "LAPACK_interface.f90" #include "math.f90" -#include "quaternions.f90" #include "rotations.f90" -#include "FEsolving.f90" #include "element.f90" #include "HDF5_utilities.f90" #include "results.f90" @@ -44,14 +42,12 @@ #include "source_damage_anisoDuctile.f90" #include "kinematics_cleavage_opening.f90" #include "kinematics_slipplane_opening.f90" -#include "crystallite.f90" #include "thermal_isothermal.f90" -#include "thermal_adiabatic.f90" #include "thermal_conduction.f90" #include "damage_none.f90" -#include "damage_local.f90" #include "damage_nonlocal.f90" #include "homogenization.f90" +#include "homogenization_mech.f90" #include "homogenization_mech_none.f90" #include "homogenization_mech_isostrain.f90" #include "homogenization_mech_RGC.f90" diff --git a/src/constitutive.f90 b/src/constitutive.f90 index 470ac4dc7..696611549 100644 --- a/src/constitutive.f90 +++ b/src/constitutive.f90 @@ -13,31 +13,119 @@ module constitutive use results use lattice use discretization - use geometry_plastic_nonlocal, only: & - geometry_plastic_nonlocal_disable + use parallelization + use HDF5_utilities + use DAMASK_interface + use results implicit none private - integer(kind(ELASTICITY_undefined_ID)), dimension(:), allocatable :: & !ToDo: old intel compiler complains about protected - phase_elasticity !< elasticity of each phase + enum, bind(c); enumerator :: & + PLASTICITY_UNDEFINED_ID, & + PLASTICITY_NONE_ID, & + PLASTICITY_ISOTROPIC_ID, & + PLASTICITY_PHENOPOWERLAW_ID, & + PLASTICITY_KINEHARDENING_ID, & + PLASTICITY_DISLOTWIN_ID, & + PLASTICITY_DISLOTUNGSTEN_ID, & + PLASTICITY_NONLOCAL_ID, & + SOURCE_UNDEFINED_ID ,& + SOURCE_THERMAL_DISSIPATION_ID, & + SOURCE_THERMAL_EXTERNALHEAT_ID, & + SOURCE_DAMAGE_ISOBRITTLE_ID, & + SOURCE_DAMAGE_ISODUCTILE_ID, & + SOURCE_DAMAGE_ANISOBRITTLE_ID, & + SOURCE_DAMAGE_ANISODUCTILE_ID, & + KINEMATICS_UNDEFINED_ID ,& + KINEMATICS_CLEAVAGE_OPENING_ID, & + KINEMATICS_SLIPPLANE_OPENING_ID, & + KINEMATICS_THERMAL_EXPANSION_ID + end enum + real(pReal), dimension(:,:,:), allocatable :: & + crystallite_subdt !< substepped time increment of each grain + type(rotation), dimension(:,:,:), allocatable :: & + crystallite_orientation !< current orientation + real(pReal), dimension(:,:,:,:,:), allocatable :: & + crystallite_F0, & !< def grad at start of FE inc + crystallite_Fe, & !< current "elastic" def grad (end of converged time step) + crystallite_subFp0,& !< plastic def grad at start of crystallite inc + crystallite_subFi0,& !< intermediate def grad at start of crystallite inc + crystallite_Lp0, & !< plastic velocitiy grad at start of FE inc + crystallite_partitionedLp0, & !< plastic velocity grad at start of homog inc + crystallite_S0, & !< 2nd Piola-Kirchhoff stress vector at start of FE inc + crystallite_partitionedS0 !< 2nd Piola-Kirchhoff stress vector at start of homog inc + real(pReal), dimension(:,:,:,:,:), allocatable, public :: & + crystallite_P, & !< 1st Piola-Kirchhoff stress per grain + crystallite_Lp, & !< current plastic velocitiy grad (end of converged time step) + crystallite_S, & !< current 2nd Piola-Kirchhoff stress vector (end of converged time step) + crystallite_partitionedF0, & !< def grad at start of homog inc + crystallite_F !< def grad to be reached at end of homog inc - integer(kind(PLASTICITY_undefined_ID)), dimension(:), allocatable :: & !ToDo: old intel compiler complains about protected + type :: tTensorContainer + real(pReal), dimension(:,:,:), allocatable :: data + end type + + type(tTensorContainer), dimension(:), allocatable :: & + constitutive_mech_Fi, & + constitutive_mech_Fi0, & + constitutive_mech_partitionedFi0, & + constitutive_mech_Li, & + constitutive_mech_Li0, & + constitutive_mech_partitionedLi0, & + constitutive_mech_Fp, & + constitutive_mech_Fp0, & + constitutive_mech_partitionedFp0 + + + type :: tNumerics + integer :: & + iJacoLpresiduum, & !< frequency of Jacobian update of residuum in Lp + nState, & !< state loop limit + nStress !< stress loop limit + real(pReal) :: & + subStepMinCryst, & !< minimum (relative) size of sub-step allowed during cutback + subStepSizeCryst, & !< size of first substep when cutback + subStepSizeLp, & !< size of first substep when cutback in Lp calculation + subStepSizeLi, & !< size of first substep when cutback in Li calculation + stepIncreaseCryst, & !< increase of next substep size when previous substep converged + rtol_crystalliteState, & !< relative tolerance in state loop + rtol_crystalliteStress, & !< relative tolerance in stress loop + atol_crystalliteStress !< absolute tolerance in stress loop + end type tNumerics + + type(tNumerics) :: num ! numerics parameters. Better name? + + type :: tDebugOptions + logical :: & + basic, & + extensive, & + selective + integer :: & + element, & + ip, & + grain + end type tDebugOptions + + type(tDebugOptions) :: debugCrystallite + + + + integer(kind(PLASTICITY_undefined_ID)), dimension(:), allocatable, public :: & phase_plasticity !< plasticity of each phase - integer(kind(SOURCE_undefined_ID)), dimension(:,:), allocatable :: & ! ToDo: old intel compiler complains about protected + integer(kind(SOURCE_undefined_ID)), dimension(:,:), allocatable :: & phase_source, & !< active sources mechanisms of each phase - phase_kinematics, & !< active kinematic mechanisms of each phase - phase_stiffnessDegradation !< active stiffness degradation mechanisms of each phase + phase_kinematics !< active kinematic mechanisms of each phase - integer, dimension(:), allocatable, public :: & ! ToDo: old intel compiler complains about protected + integer, dimension(:), allocatable, public :: & !< ToDo: should be protected (bug in Intel compiler) phase_Nsources, & !< number of source mechanisms active in each phase phase_Nkinematics, & !< number of kinematic mechanisms active in each phase phase_NstiffnessDegradations, & !< number of stiffness degradation mechanisms active in each phase phase_plasticityInstance, & !< instance of particular plasticity of each phase phase_elasticityInstance !< instance of particular elasticity of each phase - logical, dimension(:), allocatable, public :: & ! ToDo: old intel compiler complains about protected + logical, dimension(:), allocatable, public :: & ! ToDo: should be protected (bug in Intel Compiler) phase_localPlasticity !< flags phases with local constitutive law type(tPlasticState), allocatable, dimension(:), public :: & @@ -52,6 +140,7 @@ module constitutive interface +! == cleaned:begin ================================================================================= module subroutine mech_init end subroutine mech_init @@ -62,104 +151,72 @@ module constitutive end subroutine thermal_init - module function plastic_active(plastic_label) result(active_plastic) - character(len=*), intent(in) :: plastic_label - logical, dimension(:), allocatable :: active_plastic - end function plastic_active + module subroutine mech_results(group,ph) + character(len=*), intent(in) :: group + integer, intent(in) :: ph + end subroutine mech_results - module function source_active(source_label,src_length) result(active_source) - character(len=*), intent(in) :: source_label - integer, intent(in) :: src_length - logical, dimension(:,:), allocatable :: active_source - end function source_active + module subroutine damage_results(group,ph) + character(len=*), intent(in) :: group + integer, intent(in) :: ph + end subroutine damage_results - module function kinematics_active(kinematics_label,kinematics_length) result(active_kinematics) - character(len=*), intent(in) :: kinematics_label - integer, intent(in) :: kinematics_length - logical, dimension(:,:), allocatable :: active_kinematics - end function kinematics_active - module subroutine plastic_isotropic_dotState(Mp,instance,of) - real(pReal), dimension(3,3), intent(in) :: & - Mp !< Mandel stress - integer, intent(in) :: & - instance, & - of - end subroutine plastic_isotropic_dotState + module subroutine mech_restart_read(fileHandle) + integer(HID_T), intent(in) :: fileHandle + end subroutine mech_restart_read - module subroutine plastic_phenopowerlaw_dotState(Mp,instance,of) - real(pReal), dimension(3,3), intent(in) :: & - Mp !< Mandel stress - integer, intent(in) :: & - instance, & - of - end subroutine plastic_phenopowerlaw_dotState + module subroutine mech_initializeRestorationPoints(ph,me) + integer, intent(in) :: ph, me + end subroutine mech_initializeRestorationPoints - module subroutine plastic_kinehardening_dotState(Mp,instance,of) - real(pReal), dimension(3,3), intent(in) :: & - Mp !< Mandel stress - integer, intent(in) :: & - instance, & - of - end subroutine plastic_kinehardening_dotState + module subroutine constitutive_mech_windForward(ph,me) + integer, intent(in) :: ph, me + end subroutine constitutive_mech_windForward - module subroutine plastic_dislotwin_dotState(Mp,T,instance,of) - real(pReal), dimension(3,3), intent(in) :: & - Mp !< Mandel stress - real(pReal), intent(in) :: & - T - integer, intent(in) :: & - instance, & - of - end subroutine plastic_dislotwin_dotState + module subroutine constitutive_mech_forward + end subroutine constitutive_mech_forward - module subroutine plastic_disloTungsten_dotState(Mp,T,instance,of) - real(pReal), dimension(3,3), intent(in) :: & - Mp !< Mandel stress - real(pReal), intent(in) :: & - T - integer, intent(in) :: & - instance, & - of - end subroutine plastic_disloTungsten_dotState - - module subroutine plastic_nonlocal_dotState(Mp, F, Fp, Temperature,timestep, & - instance,of,ip,el) - real(pReal), dimension(3,3), intent(in) :: & - Mp !< MandelStress - real(pReal), dimension(3,3,homogenization_maxNconstituents,discretization_nIPs,discretization_Nelems), intent(in) :: & - F, & !< deformation gradient - Fp !< plastic deformation gradient - real(pReal), intent(in) :: & - Temperature, & !< temperature - timestep !< substepped crystallite time increment + module subroutine mech_restore(ip,el,includeL) integer, intent(in) :: & - instance, & - of, & - ip, & !< current integration point - el !< current element number - end subroutine plastic_nonlocal_dotState + ip, & + el + logical, intent(in) :: & + includeL + end subroutine mech_restore +! == cleaned:end =================================================================================== - module subroutine source_damage_anisoBrittle_dotState(S, ipc, ip, el) + module function crystallite_stress(dt,co,ip,el) result(converged_) + real(pReal), intent(in) :: dt + integer, intent(in) :: co, ip, el + logical :: converged_ + end function crystallite_stress + + module function constitutive_homogenizedC(co,ip,el) result(C) + integer, intent(in) :: co, ip, el + real(pReal), dimension(6,6) :: C + end function constitutive_homogenizedC + + module subroutine source_damage_anisoBrittle_dotState(S, co, ip, el) integer, intent(in) :: & - ipc, & !< component-ID of integration point + co, & !< component-ID of integration point ip, & !< integration point el !< element real(pReal), intent(in), dimension(3,3) :: & S end subroutine source_damage_anisoBrittle_dotState - module subroutine source_damage_anisoDuctile_dotState(ipc, ip, el) + module subroutine source_damage_anisoDuctile_dotState(co, ip, el) integer, intent(in) :: & - ipc, & !< component-ID of integration point + co, & !< component-ID of integration point ip, & !< integration point el !< element end subroutine source_damage_anisoDuctile_dotState - module subroutine source_damage_isoDuctile_dotState(ipc, ip, el) + module subroutine source_damage_isoDuctile_dotState(co, ip, el) integer, intent(in) :: & - ipc, & !< component-ID of integration point + co, & !< component-ID of integration point ip, & !< integration point el !< element end subroutine source_damage_isoDuctile_dotState @@ -195,23 +252,7 @@ module constitutive dTDot_dT end subroutine constitutive_thermal_getRateAndItsTangents - module function plastic_dislotwin_homogenizedC(ipc,ip,el) result(homogenizedC) - real(pReal), dimension(6,6) :: & - homogenizedC - integer, intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - end function plastic_dislotwin_homogenizedC - pure module function kinematics_thermal_expansion_initialStrain(homog,phase,offset) result(initialStrain) - integer, intent(in) :: & - phase, & - homog, & - offset - real(pReal), dimension(3,3) :: & - initialStrain - end function kinematics_thermal_expansion_initialStrain module subroutine plastic_nonlocal_updateCompatibility(orientation,instance,i,e) integer, intent(in) :: & @@ -234,9 +275,9 @@ module constitutive of end subroutine plastic_isotropic_LiAndItsTangent - module subroutine kinematics_cleavage_opening_LiAndItsTangent(Ld, dLd_dTstar, S, ipc, ip, el) + module subroutine kinematics_cleavage_opening_LiAndItsTangent(Ld, dLd_dTstar, S, co, ip, el) integer, intent(in) :: & - ipc, & !< grain number + co, & !< grain number ip, & !< integration point number el !< element number real(pReal), intent(in), dimension(3,3) :: & @@ -247,9 +288,9 @@ module constitutive dLd_dTstar !< derivative of Ld with respect to Tstar (4th-order tensor) end subroutine kinematics_cleavage_opening_LiAndItsTangent - module subroutine kinematics_slipplane_opening_LiAndItsTangent(Ld, dLd_dTstar, S, ipc, ip, el) + module subroutine kinematics_slipplane_opening_LiAndItsTangent(Ld, dLd_dTstar, S, co, ip, el) integer, intent(in) :: & - ipc, & !< grain number + co, & !< grain number ip, & !< integration point number el !< element number real(pReal), intent(in), dimension(3,3) :: & @@ -260,9 +301,9 @@ module constitutive dLd_dTstar !< derivative of Ld with respect to Tstar (4th-order tensor) end subroutine kinematics_slipplane_opening_LiAndItsTangent - module subroutine kinematics_thermal_expansion_LiAndItsTangent(Li, dLi_dTstar, ipc, ip, el) + module subroutine kinematics_thermal_expansion_LiAndItsTangent(Li, dLi_dTstar, co, ip, el) integer, intent(in) :: & - ipc, & !< grain number + co, & !< grain number ip, & !< integration point number el !< element number real(pReal), intent(out), dimension(3,3) :: & @@ -272,27 +313,9 @@ module constitutive end subroutine kinematics_thermal_expansion_LiAndItsTangent - module subroutine plastic_kinehardening_deltaState(Mp,instance,of) - real(pReal), dimension(3,3), intent(in) :: & - Mp !< Mandel stress - integer, intent(in) :: & - instance, & - of - end subroutine plastic_kinehardening_deltaState - - module subroutine plastic_nonlocal_deltaState(Mp,instance,of,ip,el) - real(pReal), dimension(3,3), intent(in) :: & - Mp + module subroutine source_damage_isoBrittle_deltaState(C, Fe, co, ip, el) integer, intent(in) :: & - instance, & - of, & - ip, & - el - end subroutine plastic_nonlocal_deltaState - - module subroutine source_damage_isoBrittle_deltaState(C, Fe, ipc, ip, el) - integer, intent(in) :: & - ipc, & !< component-ID of integration point + co, & !< component-ID of integration point ip, & !< integration point el !< element real(pReal), intent(in), dimension(3,3) :: & @@ -301,20 +324,11 @@ module constitutive C end subroutine source_damage_isoBrittle_deltaState - module subroutine plastic_results - end subroutine plastic_results - - module subroutine damage_results - end subroutine damage_results - - end interface - - interface constitutive_LpAndItsTangents module subroutine constitutive_plastic_LpAndItsTangents(Lp, dLp_dS, dLp_dFi, & - S, Fi, ipc, ip, el) + S, Fi, co, ip, el) integer, intent(in) :: & - ipc, & !< component-ID of integration point + co, & !< component-ID of integration point ip, & !< integration point el !< element real(pReal), intent(in), dimension(3,3) :: & @@ -327,27 +341,21 @@ module constitutive dLp_dFi !< derivative of Lp with respect to Fi end subroutine constitutive_plastic_LpAndItsTangents - end interface constitutive_LpAndItsTangents - interface constitutive_dependentState - - module subroutine constitutive_plastic_dependentState(F, Fp, ipc, ip, el) + module subroutine constitutive_plastic_dependentState(F, co, ip, el) integer, intent(in) :: & - ipc, & !< component-ID of integration point + co, & !< component-ID of integration point ip, & !< integration point el !< element real(pReal), intent(in), dimension(3,3) :: & - F, & !< elastic deformation gradient - Fp !< plastic deformation gradient + F !< elastic deformation gradient end subroutine constitutive_plastic_dependentState - end interface constitutive_dependentState - interface constitutive_SandItsTangents - - module subroutine constitutive_hooke_SandItsTangents(S, dS_dFe, dS_dFi, Fe, Fi, ipc, ip, el) + + module subroutine constitutive_hooke_SandItsTangents(S, dS_dFe, dS_dFi, Fe, Fi, co, ip, el) integer, intent(in) :: & - ipc, & !< component-ID of integration point + co, & !< component-ID of integration point ip, & !< integration point el !< element real(pReal), intent(in), dimension(3,3) :: & @@ -360,40 +368,56 @@ module constitutive dS_dFi !< derivative of 2nd P-K stress with respect to intermediate deformation gradient end subroutine constitutive_hooke_SandItsTangents - end interface constitutive_SandItsTangents + end interface - type :: tDebugOptions - logical :: & - basic, & - extensive, & - selective - integer :: & - element, & - ip, & - grain - end type tDebugOptions type(tDebugOptions) :: debugConstitutive public :: & constitutive_init, & constitutive_homogenizedC, & - constitutive_LpAndItsTangents, & - constitutive_dependentState, & constitutive_LiAndItsTangents, & - constitutive_initialFi, & - constitutive_SandItsTangents, & - constitutive_collectDotState, & - constitutive_deltaState, & constitutive_damage_getRateAndItsTangents, & constitutive_thermal_getRateAndItsTangents, & constitutive_results, & constitutive_allocateState, & + constitutive_forward, & + constitutive_restore, & plastic_nonlocal_updateCompatibility, & - plastic_active, & source_active, & - kinematics_active + kinematics_active, & + converged, & + crystallite_init, & + crystallite_stress, & + crystallite_stressTangent, & + crystallite_orientations, & + crystallite_push33ToRef, & + crystallite_restartWrite, & + integrateSourceState, & + crystallite_restartRead, & + constitutive_initializeRestorationPoints, & + constitutive_windForward, & + PLASTICITY_UNDEFINED_ID, & + PLASTICITY_NONE_ID, & + PLASTICITY_ISOTROPIC_ID, & + PLASTICITY_PHENOPOWERLAW_ID, & + PLASTICITY_KINEHARDENING_ID, & + PLASTICITY_DISLOTWIN_ID, & + PLASTICITY_DISLOTUNGSTEN_ID, & + PLASTICITY_NONLOCAL_ID, & + SOURCE_UNDEFINED_ID ,& + SOURCE_THERMAL_DISSIPATION_ID, & + SOURCE_THERMAL_EXTERNALHEAT_ID, & + SOURCE_DAMAGE_ISOBRITTLE_ID, & + SOURCE_DAMAGE_ISODUCTILE_ID, & + SOURCE_DAMAGE_ANISOBRITTLE_ID, & + SOURCE_DAMAGE_ANISODUCTILE_ID, & + KINEMATICS_UNDEFINED_ID ,& + KINEMATICS_CLEAVAGE_OPENING_ID, & + KINEMATICS_SLIPPLANE_OPENING_ID, & + KINEMATICS_THERMAL_EXPANSION_ID + contains @@ -403,12 +427,13 @@ contains subroutine constitutive_init integer :: & - p, & !< counter in phase loop - s !< counter in source loop + ph, & !< counter in phase loop + so !< counter in source loop class (tNode), pointer :: & debug_constitutive, & phases + debug_constitutive => config_debug%get('constitutive', defaultVal=emptyList) debugConstitutive%basic = debug_constitutive%contains('basic') debugConstitutive%extensive = debug_constitutive%contains('extensive') @@ -419,26 +444,26 @@ subroutine constitutive_init !-------------------------------------------------------------------------------------------------- ! initialize constitutive laws + print'(/,a)', ' <<<+- constitutive init -+>>>'; flush(IO_STDOUT) call mech_init call damage_init call thermal_init - print'(/,a)', ' <<<+- constitutive init -+>>>'; flush(IO_STDOUT) - phases => config_material%get('phase') + phases => config_material%get('phase') constitutive_source_maxSizeDotState = 0 - PhaseLoop2:do p = 1,phases%length + PhaseLoop2:do ph = 1,phases%length !-------------------------------------------------------------------------------------------------- ! partition and initialize state - plasticState(p)%partitionedState0 = plasticState(p)%state0 - plasticState(p)%state = plasticState(p)%partitionedState0 - forall(s = 1:phase_Nsources(p)) - sourceState(p)%p(s)%partitionedState0 = sourceState(p)%p(s)%state0 - sourceState(p)%p(s)%state = sourceState(p)%p(s)%partitionedState0 + plasticState(ph)%partitionedState0 = plasticState(ph)%state0 + plasticState(ph)%state = plasticState(ph)%partitionedState0 + forall(so = 1:phase_Nsources(ph)) + sourceState(ph)%p(so)%partitionedState0 = sourceState(ph)%p(so)%state0 + sourceState(ph)%p(so)%state = sourceState(ph)%p(so)%partitionedState0 end forall constitutive_source_maxSizeDotState = max(constitutive_source_maxSizeDotState, & - maxval(sourceState(p)%p%sizeDotState)) + maxval(sourceState(ph)%p%sizeDotState)) enddo PhaseLoop2 constitutive_plasticity_maxSizeDotState = maxval(plasticState%sizeDotState) @@ -448,7 +473,7 @@ end subroutine constitutive_init !-------------------------------------------------------------------------------------------------- !> @brief checks if a source mechanism is active or not !-------------------------------------------------------------------------------------------------- -module function source_active(source_label,src_length) result(active_source) +function source_active(source_label,src_length) result(active_source) character(len=*), intent(in) :: source_label !< name of source mechanism integer, intent(in) :: src_length !< max. number of sources in system @@ -479,8 +504,7 @@ end function source_active !-------------------------------------------------------------------------------------------------- !> @brief checks if a kinematic mechanism is active or not !-------------------------------------------------------------------------------------------------- - -module function kinematics_active(kinematics_label,kinematics_length) result(active_kinematics) +function kinematics_active(kinematics_label,kinematics_length) result(active_kinematics) character(len=*), intent(in) :: kinematics_label !< name of kinematic mechanism integer, intent(in) :: kinematics_length !< max. number of kinematics in system @@ -508,38 +532,15 @@ module function kinematics_active(kinematics_label,kinematics_length) result(ac end function kinematics_active -!-------------------------------------------------------------------------------------------------- -!> @brief returns the homogenize elasticity matrix -!> ToDo: homogenizedC66 would be more consistent -!-------------------------------------------------------------------------------------------------- -function constitutive_homogenizedC(ipc,ip,el) - - real(pReal), dimension(6,6) :: & - constitutive_homogenizedC - integer, intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el !< element - - plasticityType: select case (phase_plasticity(material_phaseAt(ipc,el))) - case (PLASTICITY_DISLOTWIN_ID) plasticityType - constitutive_homogenizedC = plastic_dislotwin_homogenizedC(ipc,ip,el) - case default plasticityType - constitutive_homogenizedC = lattice_C66(1:6,1:6,material_phaseAt(ipc,el)) - end select plasticityType - -end function constitutive_homogenizedC - - !-------------------------------------------------------------------------------------------------- !> @brief contains the constitutive equation for calculating the velocity gradient ! ToDo: MD: S is Mi? !-------------------------------------------------------------------------------------------------- subroutine constitutive_LiAndItsTangents(Li, dLi_dS, dLi_dFi, & - S, Fi, ipc, ip, el) + S, Fi, co, ip, el) integer, intent(in) :: & - ipc, & !< component-ID of integration point + co, & !< component-ID of integration point ip, & !< integration point el !< element real(pReal), intent(in), dimension(3,3) :: & @@ -568,10 +569,10 @@ subroutine constitutive_LiAndItsTangents(Li, dLi_dS, dLi_dFi, & dLi_dS = 0.0_pReal dLi_dFi = 0.0_pReal - plasticityType: select case (phase_plasticity(material_phaseAt(ipc,el))) + plasticityType: select case (phase_plasticity(material_phaseAt(co,el))) case (PLASTICITY_isotropic_ID) plasticityType - of = material_phasememberAt(ipc,ip,el) - instance = phase_plasticityInstance(material_phaseAt(ipc,el)) + of = material_phasememberAt(co,ip,el) + instance = phase_plasticityInstance(material_phaseAt(co,el)) call plastic_isotropic_LiAndItsTangent(my_Li, my_dLi_dS, S ,instance,of) case default plasticityType my_Li = 0.0_pReal @@ -581,14 +582,14 @@ subroutine constitutive_LiAndItsTangents(Li, dLi_dS, dLi_dFi, & Li = Li + my_Li dLi_dS = dLi_dS + my_dLi_dS - KinematicsLoop: do k = 1, phase_Nkinematics(material_phaseAt(ipc,el)) - kinematicsType: select case (phase_kinematics(k,material_phaseAt(ipc,el))) + KinematicsLoop: do k = 1, phase_Nkinematics(material_phaseAt(co,el)) + kinematicsType: select case (phase_kinematics(k,material_phaseAt(co,el))) case (KINEMATICS_cleavage_opening_ID) kinematicsType - call kinematics_cleavage_opening_LiAndItsTangent(my_Li, my_dLi_dS, S, ipc, ip, el) + call kinematics_cleavage_opening_LiAndItsTangent(my_Li, my_dLi_dS, S, co, ip, el) case (KINEMATICS_slipplane_opening_ID) kinematicsType - call kinematics_slipplane_opening_LiAndItsTangent(my_Li, my_dLi_dS, S, ipc, ip, el) + call kinematics_slipplane_opening_LiAndItsTangent(my_Li, my_dLi_dS, S, co, ip, el) case (KINEMATICS_thermal_expansion_ID) kinematicsType - call kinematics_thermal_expansion_LiAndItsTangent(my_Li, my_dLi_dS, ipc, ip, el) + call kinematics_thermal_expansion_LiAndItsTangent(my_Li, my_dLi_dS, co, ip, el) case default kinematicsType my_Li = 0.0_pReal my_dLi_dS = 0.0_pReal @@ -612,197 +613,116 @@ end subroutine constitutive_LiAndItsTangents !-------------------------------------------------------------------------------------------------- -!> @brief collects initial intermediate deformation gradient +!> @brief contains the constitutive equation for calculating the rate of change of microstructure !-------------------------------------------------------------------------------------------------- -pure function constitutive_initialFi(ipc, ip, el) +function constitutive_damage_collectDotState(S, co, ip, el,ph,of) result(broken) integer, intent(in) :: & - ipc, & !< component-ID of integration point + co, & !< component-ID of integration point ip, & !< integration point - el !< element - real(pReal), dimension(3,3) :: & - constitutive_initialFi !< composite initial intermediate deformation gradient + el, & !< element + ph, & + of + real(pReal), intent(in), dimension(3,3) :: & + S !< 2nd Piola Kirchhoff stress (vector notation) integer :: & - k !< counter in kinematics loop - integer :: & - phase, & - homog, offset + so !< counter in source loop + logical :: broken - constitutive_initialFi = math_I3 - phase = material_phaseAt(ipc,el) - KinematicsLoop: do k = 1, phase_Nkinematics(phase) !< Warning: small initial strain assumption - kinematicsType: select case (phase_kinematics(k,phase)) - case (KINEMATICS_thermal_expansion_ID) kinematicsType - homog = material_homogenizationAt(el) - offset = thermalMapping(homog)%p(ip,el) - constitutive_initialFi = & - constitutive_initialFi + kinematics_thermal_expansion_initialStrain(homog,phase,offset) - end select kinematicsType - enddo KinematicsLoop + broken = .false. -end function constitutive_initialFi + SourceLoop: do so = 1, phase_Nsources(ph) + + sourceType: select case (phase_source(so,ph)) + + case (SOURCE_damage_anisoBrittle_ID) sourceType + call source_damage_anisoBrittle_dotState(S, co, ip, el) ! correct stress? + + case (SOURCE_damage_isoDuctile_ID) sourceType + call source_damage_isoDuctile_dotState(co, ip, el) + + case (SOURCE_damage_anisoDuctile_ID) sourceType + call source_damage_anisoDuctile_dotState(co, ip, el) + + end select sourceType + + broken = broken .or. any(IEEE_is_NaN(sourceState(ph)%p(so)%dotState(:,of))) + + enddo SourceLoop + +end function constitutive_damage_collectDotState !-------------------------------------------------------------------------------------------------- !> @brief contains the constitutive equation for calculating the rate of change of microstructure !-------------------------------------------------------------------------------------------------- -function constitutive_collectDotState(S, FArray, Fi, FpArray, subdt, ipc, ip, el,phase,of) result(broken) +function constitutive_thermal_collectDotState(ph,me) result(broken) - integer, intent(in) :: & - ipc, & !< component-ID of integration point - ip, & !< integration point - el, & !< element - phase, & - of - real(pReal), intent(in) :: & - subdt !< timestep - real(pReal), intent(in), dimension(3,3,homogenization_maxNconstituents,discretization_nIPs,discretization_Nelems) :: & - FArray, & !< elastic deformation gradient - FpArray !< plastic deformation gradient - real(pReal), intent(in), dimension(3,3) :: & - Fi !< intermediate deformation gradient - real(pReal), intent(in), dimension(3,3) :: & - S !< 2nd Piola Kirchhoff stress (vector notation) - real(pReal), dimension(3,3) :: & - Mp - integer :: & - ho, & !< homogenization - tme, & !< thermal member position - i, & !< counter in source loop - instance + integer, intent(in) :: ph, me logical :: broken - ho = material_homogenizationAt(el) - tme = thermalMapping(ho)%p(ip,el) - instance = phase_plasticityInstance(phase) + integer :: i - Mp = matmul(matmul(transpose(Fi),Fi),S) - plasticityType: select case (phase_plasticity(phase)) + broken = .false. - case (PLASTICITY_ISOTROPIC_ID) plasticityType - call plastic_isotropic_dotState(Mp,instance,of) + SourceLoop: do i = 1, phase_Nsources(ph) - case (PLASTICITY_PHENOPOWERLAW_ID) plasticityType - call plastic_phenopowerlaw_dotState(Mp,instance,of) + if (phase_source(i,ph) == SOURCE_thermal_externalheat_ID) & + call source_thermal_externalheat_dotState(ph,me) - case (PLASTICITY_KINEHARDENING_ID) plasticityType - call plastic_kinehardening_dotState(Mp,instance,of) - - case (PLASTICITY_DISLOTWIN_ID) plasticityType - call plastic_dislotwin_dotState(Mp,temperature(ho)%p(tme),instance,of) - - case (PLASTICITY_DISLOTUNGSTEN_ID) plasticityType - call plastic_disloTungsten_dotState(Mp,temperature(ho)%p(tme),instance,of) - - case (PLASTICITY_NONLOCAL_ID) plasticityType - call plastic_nonlocal_dotState(Mp,FArray,FpArray,temperature(ho)%p(tme),subdt, & - instance,of,ip,el) - end select plasticityType - broken = any(IEEE_is_NaN(plasticState(phase)%dotState(:,of))) - - SourceLoop: do i = 1, phase_Nsources(phase) - - sourceType: select case (phase_source(i,phase)) - - case (SOURCE_damage_anisoBrittle_ID) sourceType - call source_damage_anisoBrittle_dotState(S, ipc, ip, el) ! correct stress? - - case (SOURCE_damage_isoDuctile_ID) sourceType - call source_damage_isoDuctile_dotState(ipc, ip, el) - - case (SOURCE_damage_anisoDuctile_ID) sourceType - call source_damage_anisoDuctile_dotState(ipc, ip, el) - - case (SOURCE_thermal_externalheat_ID) sourceType - call source_thermal_externalheat_dotState(phase,of) - - end select sourceType - - broken = broken .or. any(IEEE_is_NaN(sourceState(phase)%p(i)%dotState(:,of))) + broken = broken .or. any(IEEE_is_NaN(sourceState(ph)%p(i)%dotState(:,me))) enddo SourceLoop -end function constitutive_collectDotState +end function constitutive_thermal_collectDotState !-------------------------------------------------------------------------------------------------- !> @brief for constitutive models having an instantaneous change of state !> will return false if delta state is not needed/supported by the constitutive model !-------------------------------------------------------------------------------------------------- -function constitutive_deltaState(S, Fe, Fi, ipc, ip, el, phase, of) result(broken) +function constitutive_damage_deltaState(Fe, co, ip, el, ph, of) result(broken) integer, intent(in) :: & - ipc, & !< component-ID of integration point + co, & !< component-ID of integration point ip, & !< integration point el, & !< element - phase, & + ph, & of real(pReal), intent(in), dimension(3,3) :: & - S, & !< 2nd Piola Kirchhoff stress - Fe, & !< elastic deformation gradient - Fi !< intermediate deformation gradient - real(pReal), dimension(3,3) :: & - Mp + Fe !< elastic deformation gradient integer :: & - i, & - instance, & + so, & myOffset, & mySize logical :: & broken - Mp = matmul(matmul(transpose(Fi),Fi),S) - instance = phase_plasticityInstance(phase) - plasticityType: select case (phase_plasticity(phase)) + broken = .false. - case (PLASTICITY_KINEHARDENING_ID) plasticityType - call plastic_kinehardening_deltaState(Mp,instance,of) - broken = any(IEEE_is_NaN(plasticState(phase)%deltaState(:,of))) + sourceLoop: do so = 1, phase_Nsources(ph) - case (PLASTICITY_NONLOCAL_ID) plasticityType - call plastic_nonlocal_deltaState(Mp,instance,of,ip,el) - broken = any(IEEE_is_NaN(plasticState(phase)%deltaState(:,of))) - - case default - broken = .false. - - end select plasticityType - - if(.not. broken) then - select case(phase_plasticity(phase)) - case (PLASTICITY_NONLOCAL_ID,PLASTICITY_KINEHARDENING_ID) - - myOffset = plasticState(phase)%offsetDeltaState - mySize = plasticState(phase)%sizeDeltaState - plasticState(phase)%state(myOffset + 1:myOffset + mySize,of) = & - plasticState(phase)%state(myOffset + 1:myOffset + mySize,of) + plasticState(phase)%deltaState(1:mySize,of) - end select - endif - - - sourceLoop: do i = 1, phase_Nsources(phase) - - sourceType: select case (phase_source(i,phase)) + sourceType: select case (phase_source(so,ph)) case (SOURCE_damage_isoBrittle_ID) sourceType - call source_damage_isoBrittle_deltaState (constitutive_homogenizedC(ipc,ip,el), Fe, & - ipc, ip, el) - broken = broken .or. any(IEEE_is_NaN(sourceState(phase)%p(i)%deltaState(:,of))) + call source_damage_isoBrittle_deltaState (constitutive_homogenizedC(co,ip,el), Fe, & + co, ip, el) + broken = any(IEEE_is_NaN(sourceState(ph)%p(so)%deltaState(:,of))) if(.not. broken) then - myOffset = sourceState(phase)%p(i)%offsetDeltaState - mySize = sourceState(phase)%p(i)%sizeDeltaState - sourceState(phase)%p(i)%state(myOffset + 1: myOffset + mySize,of) = & - sourceState(phase)%p(i)%state(myOffset + 1: myOffset + mySize,of) + sourceState(phase)%p(i)%deltaState(1:mySize,of) + myOffset = sourceState(ph)%p(so)%offsetDeltaState + mySize = sourceState(ph)%p(so)%sizeDeltaState + sourceState(ph)%p(so)%state(myOffset + 1: myOffset + mySize,of) = & + sourceState(ph)%p(so)%state(myOffset + 1: myOffset + mySize,of) + sourceState(ph)%p(so)%deltaState(1:mySize,of) endif end select sourceType enddo SourceLoop -end function constitutive_deltaState +end function constitutive_damage_deltaState !-------------------------------------------------------------------------------------------------- @@ -819,34 +739,696 @@ subroutine constitutive_allocateState(state, & sizeDotState, & sizeDeltaState + state%sizeState = sizeState state%sizeDotState = sizeDotState state%sizeDeltaState = sizeDeltaState state%offsetDeltaState = sizeState-sizeDeltaState ! deltaState occupies latter part of state by definition - allocate(state%atol (sizeState), source=0.0_pReal) - allocate(state%state0 (sizeState,Nconstituents), source=0.0_pReal) + allocate(state%atol (sizeState), source=0.0_pReal) + allocate(state%state0 (sizeState,Nconstituents), source=0.0_pReal) allocate(state%partitionedState0(sizeState,Nconstituents), source=0.0_pReal) - allocate(state%subState0 (sizeState,Nconstituents), source=0.0_pReal) - allocate(state%state (sizeState,Nconstituents), source=0.0_pReal) + allocate(state%subState0 (sizeState,Nconstituents), source=0.0_pReal) + allocate(state%state (sizeState,Nconstituents), source=0.0_pReal) - allocate(state%dotState (sizeDotState,Nconstituents), source=0.0_pReal) + allocate(state%dotState (sizeDotState,Nconstituents), source=0.0_pReal) - allocate(state%deltaState(sizeDeltaState,Nconstituents), source=0.0_pReal) + allocate(state%deltaState (sizeDeltaState,Nconstituents), source=0.0_pReal) end subroutine constitutive_allocateState +!-------------------------------------------------------------------------------------------------- +!> @brief Restore data after homog cutback. +!-------------------------------------------------------------------------------------------------- +subroutine constitutive_restore(ip,el,includeL) + + logical, intent(in) :: includeL + integer, intent(in) :: & + ip, & !< integration point number + el !< element number + + integer :: & + co, & !< constituent number + so + + + do co = 1,homogenization_Nconstituents(material_homogenizationAt(el)) + do so = 1, phase_Nsources(material_phaseAt(co,el)) + sourceState(material_phaseAt(co,el))%p(so)%state( :,material_phasememberAt(co,ip,el)) = & + sourceState(material_phaseAt(co,el))%p(so)%partitionedState0(:,material_phasememberAt(co,ip,el)) + enddo + enddo + + call mech_restore(ip,el,includeL) + +end subroutine constitutive_restore + + +!-------------------------------------------------------------------------------------------------- +!> @brief Forward data after successful increment. +! ToDo: Any guessing for the current states possible? +!-------------------------------------------------------------------------------------------------- +subroutine constitutive_forward + + integer :: i, j + + crystallite_F0 = crystallite_F + crystallite_Lp0 = crystallite_Lp + crystallite_S0 = crystallite_S + + call constitutive_mech_forward() + + do i = 1, size(sourceState) + do j = 1,phase_Nsources(i) + sourceState(i)%p(j)%state0 = sourceState(i)%p(j)%state + enddo; enddo + +end subroutine constitutive_forward + + !-------------------------------------------------------------------------------------------------- !> @brief writes constitutive results to HDF5 output file !-------------------------------------------------------------------------------------------------- subroutine constitutive_results - call plastic_results - call damage_results + integer :: ph + character(len=:), allocatable :: group + + + call results_closeGroup(results_addGroup('/current/phase/')) + + do ph = 1, size(material_name_phase) + + group = '/current/phase/'//trim(material_name_phase(ph))//'/' + call results_closeGroup(results_addGroup(group)) + + call mech_results(group,ph) + call damage_results(group,ph) + + enddo end subroutine constitutive_results +!-------------------------------------------------------------------------------------------------- +!> @brief allocates and initialize per grain variables +!-------------------------------------------------------------------------------------------------- +subroutine crystallite_init + + integer :: & + Nconstituents, & + ph, & + me, & + co, & !< counter in integration point component loop + ip, & !< counter in integration point loop + el, & !< counter in element loop + cMax, & !< maximum number of integration point components + iMax, & !< maximum number of integration points + eMax !< maximum number of elements + + + class(tNode), pointer :: & + num_crystallite, & + debug_crystallite, & ! pointer to debug options for crystallite + phases, & + phase, & + mech + + + print'(/,a)', ' <<<+- crystallite init -+>>>' + + debug_crystallite => config_debug%get('crystallite', defaultVal=emptyList) + debugCrystallite%extensive = debug_crystallite%contains('extensive') + + cMax = homogenization_maxNconstituents + iMax = discretization_nIPs + eMax = discretization_Nelems + + allocate(crystallite_F(3,3,cMax,iMax,eMax),source=0.0_pReal) + + allocate(crystallite_S0, & + crystallite_F0,crystallite_Lp0, & + crystallite_partitionedS0, & + crystallite_partitionedF0,& + crystallite_partitionedLp0, & + crystallite_S,crystallite_P, & + crystallite_Fe,crystallite_Lp, & + crystallite_subFp0,crystallite_subFi0, & + source = crystallite_F) + + allocate(crystallite_subdt(cMax,iMax,eMax),source=0.0_pReal) + allocate(crystallite_orientation(cMax,iMax,eMax)) + + num_crystallite => config_numerics%get('crystallite',defaultVal=emptyDict) + + num%subStepMinCryst = num_crystallite%get_asFloat ('subStepMin', defaultVal=1.0e-3_pReal) + num%subStepSizeCryst = num_crystallite%get_asFloat ('subStepSize', defaultVal=0.25_pReal) + num%stepIncreaseCryst = num_crystallite%get_asFloat ('stepIncrease', defaultVal=1.5_pReal) + num%subStepSizeLp = num_crystallite%get_asFloat ('subStepSizeLp', defaultVal=0.5_pReal) + num%subStepSizeLi = num_crystallite%get_asFloat ('subStepSizeLi', defaultVal=0.5_pReal) + num%rtol_crystalliteState = num_crystallite%get_asFloat ('rtol_State', defaultVal=1.0e-6_pReal) + num%rtol_crystalliteStress = num_crystallite%get_asFloat ('rtol_Stress', defaultVal=1.0e-6_pReal) + num%atol_crystalliteStress = num_crystallite%get_asFloat ('atol_Stress', defaultVal=1.0e-8_pReal) + num%iJacoLpresiduum = num_crystallite%get_asInt ('iJacoLpresiduum', defaultVal=1) + num%nState = num_crystallite%get_asInt ('nState', defaultVal=20) + num%nStress = num_crystallite%get_asInt ('nStress', defaultVal=40) + + if(num%subStepMinCryst <= 0.0_pReal) call IO_error(301,ext_msg='subStepMinCryst') + if(num%subStepSizeCryst <= 0.0_pReal) call IO_error(301,ext_msg='subStepSizeCryst') + if(num%stepIncreaseCryst <= 0.0_pReal) call IO_error(301,ext_msg='stepIncreaseCryst') + + if(num%subStepSizeLp <= 0.0_pReal) call IO_error(301,ext_msg='subStepSizeLp') + if(num%subStepSizeLi <= 0.0_pReal) call IO_error(301,ext_msg='subStepSizeLi') + + if(num%rtol_crystalliteState <= 0.0_pReal) call IO_error(301,ext_msg='rtol_crystalliteState') + if(num%rtol_crystalliteStress <= 0.0_pReal) call IO_error(301,ext_msg='rtol_crystalliteStress') + if(num%atol_crystalliteStress <= 0.0_pReal) call IO_error(301,ext_msg='atol_crystalliteStress') + + if(num%iJacoLpresiduum < 1) call IO_error(301,ext_msg='iJacoLpresiduum') + + if(num%nState < 1) call IO_error(301,ext_msg='nState') + if(num%nStress< 1) call IO_error(301,ext_msg='nStress') + + + phases => config_material%get('phase') + + allocate(constitutive_mech_Fi(phases%length)) + allocate(constitutive_mech_Fi0(phases%length)) + allocate(constitutive_mech_partitionedFi0(phases%length)) + allocate(constitutive_mech_Fp(phases%length)) + allocate(constitutive_mech_Fp0(phases%length)) + allocate(constitutive_mech_partitionedFp0(phases%length)) + allocate(constitutive_mech_Li(phases%length)) + allocate(constitutive_mech_Li0(phases%length)) + allocate(constitutive_mech_partitionedLi0(phases%length)) + do ph = 1, phases%length + Nconstituents = count(material_phaseAt == ph) * discretization_nIPs + + allocate(constitutive_mech_Fi(ph)%data(3,3,Nconstituents)) + allocate(constitutive_mech_Fi0(ph)%data(3,3,Nconstituents)) + allocate(constitutive_mech_partitionedFi0(ph)%data(3,3,Nconstituents)) + allocate(constitutive_mech_Fp(ph)%data(3,3,Nconstituents)) + allocate(constitutive_mech_Fp0(ph)%data(3,3,Nconstituents)) + allocate(constitutive_mech_partitionedFp0(ph)%data(3,3,Nconstituents)) + allocate(constitutive_mech_Li(ph)%data(3,3,Nconstituents)) + allocate(constitutive_mech_Li0(ph)%data(3,3,Nconstituents)) + allocate(constitutive_mech_partitionedLi0(ph)%data(3,3,Nconstituents)) + enddo + + print'(a42,1x,i10)', ' # of elements: ', eMax + print'(a42,1x,i10)', ' # of integration points/element: ', iMax + print'(a42,1x,i10)', 'max # of constituents/integration point: ', cMax + flush(IO_STDOUT) + + !$OMP PARALLEL DO PRIVATE(ph,me) + do el = 1, size(material_phaseMemberAt,3); do ip = 1, size(material_phaseMemberAt,2) + do co = 1, homogenization_Nconstituents(material_homogenizationAt(el)) + + ph = material_phaseAt(co,el) + me = material_phaseMemberAt(co,ip,el) + constitutive_mech_Fp0(ph)%data(1:3,1:3,me) = material_orientation0(co,ip,el)%asMatrix() ! Fp reflects initial orientation (see 10.1016/j.actamat.2006.01.005) + constitutive_mech_Fp0(ph)%data(1:3,1:3,me) = constitutive_mech_Fp0(ph)%data(1:3,1:3,me) & + / math_det33(constitutive_mech_Fp0(ph)%data(1:3,1:3,me))**(1.0_pReal/3.0_pReal) + constitutive_mech_Fi0(ph)%data(1:3,1:3,me) = math_I3 + + crystallite_F0(1:3,1:3,co,ip,el) = math_I3 + + crystallite_Fe(1:3,1:3,co,ip,el) = math_inv33(matmul(constitutive_mech_Fi0(ph)%data(1:3,1:3,me), & + constitutive_mech_Fp0(ph)%data(1:3,1:3,me))) ! assuming that euler angles are given in internal strain free configuration + constitutive_mech_Fp(ph)%data(1:3,1:3,me) = constitutive_mech_Fp0(ph)%data(1:3,1:3,me) + constitutive_mech_Fi(ph)%data(1:3,1:3,me) = constitutive_mech_Fi0(ph)%data(1:3,1:3,me) + + constitutive_mech_partitionedFi0(ph)%data(1:3,1:3,me) = constitutive_mech_Fi0(ph)%data(1:3,1:3,me) + constitutive_mech_partitionedFp0(ph)%data(1:3,1:3,me) = constitutive_mech_Fp0(ph)%data(1:3,1:3,me) + + enddo + enddo; enddo + !$OMP END PARALLEL DO + + crystallite_partitionedF0 = crystallite_F0 + crystallite_F = crystallite_F0 + + + !$OMP PARALLEL DO PRIVATE(ph,me) + do el = 1, size(material_phaseMemberAt,3) + do ip = 1, size(material_phaseMemberAt,2) + do co = 1,homogenization_Nconstituents(material_homogenizationAt(el)) + ph = material_phaseAt(co,el) + me = material_phaseMemberAt(co,ip,el) + call crystallite_orientations(co,ip,el) + call constitutive_plastic_dependentState(crystallite_partitionedF0(1:3,1:3,co,ip,el),co,ip,el) ! update dependent state variables to be consistent with basic states + enddo + enddo + enddo + !$OMP END PARALLEL DO + + +end subroutine crystallite_init + + +!-------------------------------------------------------------------------------------------------- +!> @brief Backup data for homog cutback. +!-------------------------------------------------------------------------------------------------- +subroutine constitutive_initializeRestorationPoints(ip,el) + + integer, intent(in) :: & + ip, & !< integration point number + el !< element number + integer :: & + co, & !< constituent number + so,ph, me + + do co = 1,homogenization_Nconstituents(material_homogenizationAt(el)) + ph = material_phaseAt(co,el) + me = material_phaseMemberAt(co,ip,el) + crystallite_partitionedLp0(1:3,1:3,co,ip,el) = crystallite_Lp0(1:3,1:3,co,ip,el) + crystallite_partitionedF0(1:3,1:3,co,ip,el) = crystallite_F0(1:3,1:3,co,ip,el) + crystallite_partitionedS0(1:3,1:3,co,ip,el) = crystallite_S0(1:3,1:3,co,ip,el) + + call mech_initializeRestorationPoints(ph,me) + + do so = 1, phase_Nsources(material_phaseAt(co,el)) + sourceState(material_phaseAt(co,el))%p(so)%partitionedState0(:,material_phasememberAt(co,ip,el)) = & + sourceState(material_phaseAt(co,el))%p(so)%state0( :,material_phasememberAt(co,ip,el)) + enddo + enddo + +end subroutine constitutive_initializeRestorationPoints + + +!-------------------------------------------------------------------------------------------------- +!> @brief Wind homog inc forward. +!-------------------------------------------------------------------------------------------------- +subroutine constitutive_windForward(ip,el) + + integer, intent(in) :: & + ip, & !< integration point number + el !< element number + + integer :: & + co, & !< constituent number + so, ph, me + + + do co = 1,homogenization_Nconstituents(material_homogenizationAt(el)) + ph = material_phaseAt(co,el) + me = material_phaseMemberAt(co,ip,el) + crystallite_partitionedF0 (1:3,1:3,co,ip,el) = crystallite_F (1:3,1:3,co,ip,el) + crystallite_partitionedLp0(1:3,1:3,co,ip,el) = crystallite_Lp(1:3,1:3,co,ip,el) + crystallite_partitionedS0 (1:3,1:3,co,ip,el) = crystallite_S (1:3,1:3,co,ip,el) + + call constitutive_mech_windForward(ph,me) + do so = 1, phase_Nsources(material_phaseAt(co,el)) + sourceState(ph)%p(so)%partitionedState0(:,me) = sourceState(ph)%p(so)%state(:,me) + enddo + enddo + +end subroutine constitutive_windForward + + +!-------------------------------------------------------------------------------------------------- +!> @brief Calculate tangent (dPdF). +!-------------------------------------------------------------------------------------------------- +function crystallite_stressTangent(co,ip,el) result(dPdF) + + real(pReal), dimension(3,3,3,3) :: dPdF + integer, intent(in) :: & + co, & !< counter in constituent loop + ip, & !< counter in integration point loop + el !< counter in element loop + + integer :: & + o, & + p, ph, me + real(pReal), dimension(3,3) :: devNull, & + invSubFp0,invSubFi0,invFp,invFi, & + temp_33_1, temp_33_2, temp_33_3 + real(pReal), dimension(3,3,3,3) :: dSdFe, & + dSdF, & + dSdFi, & + dLidS, & ! tangent in lattice configuration + dLidFi, & + dLpdS, & + dLpdFi, & + dFidS, & + dFpinvdF, & + rhs_3333, & + lhs_3333, & + temp_3333 + real(pReal), dimension(9,9):: temp_99 + logical :: error + + + ph = material_phaseAt(co,el) + me = material_phaseMemberAt(co,ip,el) + + call constitutive_hooke_SandItsTangents(devNull,dSdFe,dSdFi, & + crystallite_Fe(1:3,1:3,co,ip,el), & + constitutive_mech_Fi(ph)%data(1:3,1:3,me),co,ip,el) + call constitutive_LiAndItsTangents(devNull,dLidS,dLidFi, & + crystallite_S (1:3,1:3,co,ip,el), & + constitutive_mech_Fi(ph)%data(1:3,1:3,me), & + co,ip,el) + + invFp = math_inv33(constitutive_mech_Fp(ph)%data(1:3,1:3,me)) + invFi = math_inv33(constitutive_mech_Fi(ph)%data(1:3,1:3,me)) + invSubFp0 = math_inv33(crystallite_subFp0(1:3,1:3,co,ip,el)) + invSubFi0 = math_inv33(crystallite_subFi0(1:3,1:3,co,ip,el)) + + if (sum(abs(dLidS)) < tol_math_check) then + dFidS = 0.0_pReal + else + lhs_3333 = 0.0_pReal; rhs_3333 = 0.0_pReal + do o=1,3; do p=1,3 + lhs_3333(1:3,1:3,o,p) = lhs_3333(1:3,1:3,o,p) & + + crystallite_subdt(co,ip,el)*matmul(invSubFi0,dLidFi(1:3,1:3,o,p)) + lhs_3333(1:3,o,1:3,p) = lhs_3333(1:3,o,1:3,p) & + + invFi*invFi(p,o) + rhs_3333(1:3,1:3,o,p) = rhs_3333(1:3,1:3,o,p) & + - crystallite_subdt(co,ip,el)*matmul(invSubFi0,dLidS(1:3,1:3,o,p)) + enddo; enddo + call math_invert(temp_99,error,math_3333to99(lhs_3333)) + if (error) then + call IO_warning(warning_ID=600,el=el,ip=ip,g=co, & + ext_msg='inversion error in analytic tangent calculation') + dFidS = 0.0_pReal + else + dFidS = math_mul3333xx3333(math_99to3333(temp_99),rhs_3333) + endif + dLidS = math_mul3333xx3333(dLidFi,dFidS) + dLidS + endif + + call constitutive_plastic_LpAndItsTangents(devNull,dLpdS,dLpdFi, & + crystallite_S (1:3,1:3,co,ip,el), & + constitutive_mech_Fi(ph)%data(1:3,1:3,me),co,ip,el) + dLpdS = math_mul3333xx3333(dLpdFi,dFidS) + dLpdS + +!-------------------------------------------------------------------------------------------------- +! calculate dSdF + temp_33_1 = transpose(matmul(invFp,invFi)) + temp_33_2 = matmul(crystallite_F(1:3,1:3,co,ip,el),invSubFp0) + temp_33_3 = matmul(matmul(crystallite_F(1:3,1:3,co,ip,el),invFp), invSubFi0) + + do o=1,3; do p=1,3 + rhs_3333(p,o,1:3,1:3) = matmul(dSdFe(p,o,1:3,1:3),temp_33_1) + temp_3333(1:3,1:3,p,o) = matmul(matmul(temp_33_2,dLpdS(1:3,1:3,p,o)), invFi) & + + matmul(temp_33_3,dLidS(1:3,1:3,p,o)) + enddo; enddo + lhs_3333 = crystallite_subdt(co,ip,el)*math_mul3333xx3333(dSdFe,temp_3333) & + + math_mul3333xx3333(dSdFi,dFidS) + + call math_invert(temp_99,error,math_eye(9)+math_3333to99(lhs_3333)) + if (error) then + call IO_warning(warning_ID=600,el=el,ip=ip,g=co, & + ext_msg='inversion error in analytic tangent calculation') + dSdF = rhs_3333 + else + dSdF = math_mul3333xx3333(math_99to3333(temp_99),rhs_3333) + endif + +!-------------------------------------------------------------------------------------------------- +! calculate dFpinvdF + temp_3333 = math_mul3333xx3333(dLpdS,dSdF) + do o=1,3; do p=1,3 + dFpinvdF(1:3,1:3,p,o) = -crystallite_subdt(co,ip,el) & + * matmul(invSubFp0, matmul(temp_3333(1:3,1:3,p,o),invFi)) + enddo; enddo + +!-------------------------------------------------------------------------------------------------- +! assemble dPdF + temp_33_1 = matmul(crystallite_S(1:3,1:3,co,ip,el),transpose(invFp)) + temp_33_2 = matmul(crystallite_F(1:3,1:3,co,ip,el),invFp) + temp_33_3 = matmul(temp_33_2,crystallite_S(1:3,1:3,co,ip,el)) + + dPdF = 0.0_pReal + do p=1,3 + dPdF(p,1:3,p,1:3) = transpose(matmul(invFp,temp_33_1)) + enddo + do o=1,3; do p=1,3 + dPdF(1:3,1:3,p,o) = dPdF(1:3,1:3,p,o) & + + matmul(matmul(crystallite_F(1:3,1:3,co,ip,el), & + dFpinvdF(1:3,1:3,p,o)),temp_33_1) & + + matmul(matmul(temp_33_2,dSdF(1:3,1:3,p,o)), & + transpose(invFp)) & + + matmul(temp_33_3,transpose(dFpinvdF(1:3,1:3,p,o))) + enddo; enddo + +end function crystallite_stressTangent + + +!-------------------------------------------------------------------------------------------------- +!> @brief calculates orientations +!-------------------------------------------------------------------------------------------------- +subroutine crystallite_orientations(co,ip,el) + + integer, intent(in) :: & + co, & !< counter in integration point component loop + ip, & !< counter in integration point loop + el !< counter in element loop + + + call crystallite_orientation(co,ip,el)%fromMatrix(transpose(math_rotationalPart(crystallite_Fe(1:3,1:3,co,ip,el)))) + + if (plasticState(material_phaseAt(1,el))%nonlocal) & + call plastic_nonlocal_updateCompatibility(crystallite_orientation, & + phase_plasticityInstance(material_phaseAt(1,el)),ip,el) + + +end subroutine crystallite_orientations + + +!-------------------------------------------------------------------------------------------------- +!> @brief Map 2nd order tensor to reference config +!-------------------------------------------------------------------------------------------------- +function crystallite_push33ToRef(co,ip,el, tensor33) + + real(pReal), dimension(3,3), intent(in) :: tensor33 + real(pReal), dimension(3,3) :: T + integer, intent(in):: & + el, & + ip, & + co + + real(pReal), dimension(3,3) :: crystallite_push33ToRef + + + T = matmul(material_orientation0(co,ip,el)%asMatrix(), & ! ToDo: initial orientation correct? + transpose(math_inv33(crystallite_F(1:3,1:3,co,ip,el)))) + crystallite_push33ToRef = matmul(transpose(T),matmul(tensor33,T)) + +end function crystallite_push33ToRef + + +!-------------------------------------------------------------------------------------------------- +!> @brief integrate stress, state with adaptive 1st order explicit Euler method +!> using Fixed Point Iteration to adapt the stepsize +!-------------------------------------------------------------------------------------------------- +function integrateSourceState(dt,co,ip,el) result(broken) + + real(pReal), intent(in) :: dt + integer, intent(in) :: & + el, & !< element index in element loop + ip, & !< integration point index in ip loop + co !< grain index in grain loop + + integer :: & + NiterationState, & !< number of iterations in state loop + ph, & + me, & + so + integer, dimension(maxval(phase_Nsources)) :: & + size_so + real(pReal) :: & + zeta + real(pReal), dimension(constitutive_source_maxSizeDotState) :: & + r ! state residuum + real(pReal), dimension(constitutive_source_maxSizeDotState,2,maxval(phase_Nsources)) :: source_dotState + logical :: & + broken, converged_ + + + ph = material_phaseAt(co,el) + me = material_phaseMemberAt(co,ip,el) + + converged_ = .true. + broken = constitutive_thermal_collectDotState(ph,me) + broken = broken .or. constitutive_damage_collectDotState(crystallite_S(1:3,1:3,co,ip,el), co,ip,el,ph,me) + if(broken) return + + do so = 1, phase_Nsources(ph) + size_so(so) = sourceState(ph)%p(so)%sizeDotState + sourceState(ph)%p(so)%state(1:size_so(so),me) = sourceState(ph)%p(so)%subState0(1:size_so(so),me) & + + sourceState(ph)%p(so)%dotState (1:size_so(so),me) * dt + source_dotState(1:size_so(so),2,so) = 0.0_pReal + enddo + + iteration: do NiterationState = 1, num%nState + + do so = 1, phase_Nsources(ph) + if(nIterationState > 1) source_dotState(1:size_so(so),2,so) = source_dotState(1:size_so(so),1,so) + source_dotState(1:size_so(so),1,so) = sourceState(ph)%p(so)%dotState(:,me) + enddo + + broken = constitutive_thermal_collectDotState(ph,me) + broken = broken .or. constitutive_damage_collectDotState(crystallite_S(1:3,1:3,co,ip,el), co,ip,el,ph,me) + if(broken) exit iteration + + do so = 1, phase_Nsources(ph) + zeta = damper(sourceState(ph)%p(so)%dotState(:,me), & + source_dotState(1:size_so(so),1,so),& + source_dotState(1:size_so(so),2,so)) + sourceState(ph)%p(so)%dotState(:,me) = sourceState(ph)%p(so)%dotState(:,me) * zeta & + + source_dotState(1:size_so(so),1,so)* (1.0_pReal - zeta) + r(1:size_so(so)) = sourceState(ph)%p(so)%state (1:size_so(so),me) & + - sourceState(ph)%p(so)%subState0(1:size_so(so),me) & + - sourceState(ph)%p(so)%dotState (1:size_so(so),me) * dt + sourceState(ph)%p(so)%state(1:size_so(so),me) = sourceState(ph)%p(so)%state(1:size_so(so),me) & + - r(1:size_so(so)) + converged_ = converged_ .and. converged(r(1:size_so(so)), & + sourceState(ph)%p(so)%state(1:size_so(so),me), & + sourceState(ph)%p(so)%atol(1:size_so(so))) + enddo + + if(converged_) then + broken = constitutive_damage_deltaState(crystallite_Fe(1:3,1:3,co,ip,el),co,ip,el,ph,me) + exit iteration + endif + + enddo iteration + + broken = broken .or. .not. converged_ + + + contains + + !-------------------------------------------------------------------------------------------------- + !> @brief calculate the damping for correction of state and dot state + !-------------------------------------------------------------------------------------------------- + real(pReal) pure function damper(current,previous,previous2) + + real(pReal), dimension(:), intent(in) ::& + current, previous, previous2 + + real(pReal) :: dot_prod12, dot_prod22 + + dot_prod12 = dot_product(current - previous, previous - previous2) + dot_prod22 = dot_product(previous - previous2, previous - previous2) + if ((dot_product(current,previous) < 0.0_pReal .or. dot_prod12 < 0.0_pReal) .and. dot_prod22 > 0.0_pReal) then + damper = 0.75_pReal + 0.25_pReal * tanh(2.0_pReal + 4.0_pReal * dot_prod12 / dot_prod22) + else + damper = 1.0_pReal + endif + + end function damper + +end function integrateSourceState + + +!-------------------------------------------------------------------------------------------------- +!> @brief determines whether a point is converged +!-------------------------------------------------------------------------------------------------- +logical pure function converged(residuum,state,atol) + + real(pReal), intent(in), dimension(:) ::& + residuum, state, atol + real(pReal) :: & + rTol + + rTol = num%rTol_crystalliteState + + converged = all(abs(residuum) <= max(atol, rtol*abs(state))) + +end function converged + + +!-------------------------------------------------------------------------------------------------- +!> @brief Write current restart information (Field and constitutive data) to file. +! ToDo: Merge data into one file for MPI, move state to constitutive and homogenization, respectively +!-------------------------------------------------------------------------------------------------- +subroutine crystallite_restartWrite + + integer :: ph + integer(HID_T) :: fileHandle, groupHandle + character(len=pStringLen) :: fileName, datasetName + + print*, ' writing field and constitutive data required for restart to file';flush(IO_STDOUT) + + write(fileName,'(a,i0,a)') trim(getSolverJobName())//'_',worldrank,'.hdf5' + fileHandle = HDF5_openFile(fileName,'a') + + call HDF5_write(fileHandle,crystallite_F,'F') + call HDF5_write(fileHandle,crystallite_Lp, 'L_p') + call HDF5_write(fileHandle,crystallite_S, 'S') + + groupHandle = HDF5_addGroup(fileHandle,'phase') + do ph = 1,size(material_name_phase) + write(datasetName,'(i0,a)') ph,'_omega' + call HDF5_write(groupHandle,plasticState(ph)%state,datasetName) + write(datasetName,'(i0,a)') ph,'_F_i' + call HDF5_write(groupHandle,constitutive_mech_Fi(ph)%data,datasetName) + write(datasetName,'(i0,a)') ph,'_L_i' + call HDF5_write(groupHandle,constitutive_mech_Li(ph)%data,datasetName) + write(datasetName,'(i0,a)') ph,'_F_p' + call HDF5_write(groupHandle,constitutive_mech_Fp(ph)%data,datasetName) + enddo + call HDF5_closeGroup(groupHandle) + + groupHandle = HDF5_addGroup(fileHandle,'homogenization') + do ph = 1, size(material_name_homogenization) + write(datasetName,'(i0,a)') ph,'_omega' + call HDF5_write(groupHandle,homogState(ph)%state,datasetName) + enddo + call HDF5_closeGroup(groupHandle) + + call HDF5_closeFile(fileHandle) + +end subroutine crystallite_restartWrite + + +!-------------------------------------------------------------------------------------------------- +!> @brief Read data for restart +! ToDo: Merge data into one file for MPI, move state to constitutive and homogenization, respectively +!-------------------------------------------------------------------------------------------------- +subroutine crystallite_restartRead + + integer :: ph + integer(HID_T) :: fileHandle, groupHandle + character(len=pStringLen) :: fileName, datasetName + + print'(/,a,i0,a)', ' reading restart information of increment from file' + + write(fileName,'(a,i0,a)') trim(getSolverJobName())//'_',worldrank,'.hdf5' + fileHandle = HDF5_openFile(fileName) + + call HDF5_read(fileHandle,crystallite_F0, 'F') + call HDF5_read(fileHandle,crystallite_Lp0,'L_p') + call HDF5_read(fileHandle,crystallite_S0, 'S') + + groupHandle = HDF5_openGroup(fileHandle,'phase') + do ph = 1,size(material_name_phase) + write(datasetName,'(i0,a)') ph,'_omega' + call HDF5_read(groupHandle,plasticState(ph)%state0,datasetName) + write(datasetName,'(i0,a)') ph,'_F_i' + call HDF5_read(groupHandle,constitutive_mech_Fi0(ph)%data,datasetName) + write(datasetName,'(i0,a)') ph,'_L_i' + call HDF5_read(groupHandle,constitutive_mech_Li0(ph)%data,datasetName) + write(datasetName,'(i0,a)') ph,'_F_p' + call HDF5_read(groupHandle,constitutive_mech_Fp0(ph)%data,datasetName) + enddo + call HDF5_closeGroup(groupHandle) + + groupHandle = HDF5_openGroup(fileHandle,'homogenization') + do ph = 1,size(material_name_homogenization) + write(datasetName,'(i0,a)') ph,'_omega' + call HDF5_read(groupHandle,homogState(ph)%state0,datasetName) + enddo + call HDF5_closeGroup(groupHandle) + + call HDF5_closeFile(fileHandle) + +end subroutine crystallite_restartRead + + end module constitutive diff --git a/src/constitutive_damage.f90 b/src/constitutive_damage.f90 index a864ca1b8..3ce614666 100644 --- a/src/constitutive_damage.f90 +++ b/src/constitutive_damage.f90 @@ -1,5 +1,5 @@ !---------------------------------------------------------------------------------------------------- -!> @brief internal microstructure state for all damage sources and kinematics constitutive models +!> @brief internal microstructure state for all damage sources and kinematics constitutive models !---------------------------------------------------------------------------------------------------- submodule(constitutive) constitutive_damage @@ -8,7 +8,7 @@ submodule(constitutive) constitutive_damage module function source_damage_anisoBrittle_init(source_length) result(mySources) integer, intent(in) :: source_length logical, dimension(:,:), allocatable :: mySources - end function source_damage_anisoBrittle_init + end function source_damage_anisoBrittle_init module function source_damage_anisoDuctile_init(source_length) result(mySources) integer, intent(in) :: source_length @@ -23,7 +23,7 @@ submodule(constitutive) constitutive_damage module function source_damage_isoDuctile_init(source_length) result(mySources) integer, intent(in) :: source_length logical, dimension(:,:), allocatable :: mySources - end function source_damage_isoDuctile_init + end function source_damage_isoDuctile_init module function kinematics_cleavage_opening_init(kinematics_length) result(myKinematics) integer, intent(in) :: kinematics_length @@ -39,14 +39,14 @@ submodule(constitutive) constitutive_damage module subroutine source_damage_anisobrittle_getRateAndItsTangent(localphiDot, dLocalphiDot_dPhi, phi, phase, constituent) integer, intent(in) :: & phase, & !< phase ID of element - constituent !< position of element within its phase instance + constituent !< position of element within its phase instance real(pReal), intent(in) :: & - phi !< damage parameter + phi !< damage parameter real(pReal), intent(out) :: & localphiDot, & dLocalphiDot_dPhi end subroutine source_damage_anisoBrittle_getRateAndItsTangent - + module subroutine source_damage_anisoDuctile_getRateAndItsTangent(localphiDot, dLocalphiDot_dPhi, phi, phase, constituent) integer, intent(in) :: & phase, & !< phase ID of element @@ -129,7 +129,7 @@ module subroutine damage_init allocate(sourceState(ph)%p(phase_Nsources(ph))) enddo - allocate(phase_source(maxval(phase_Nsources),phases%length), source = SOURCE_undefined_ID) + allocate(phase_source(maxval(phase_Nsources),phases%length), source = SOURCE_undefined_ID) ! initialize source mechanisms if(maxval(phase_Nsources) /= 0) then @@ -141,19 +141,19 @@ module subroutine damage_init !-------------------------------------------------------------------------------------------------- ! initialize kinematic mechanisms - allocate(phase_Nkinematics(phases%length),source = 0) + allocate(phase_Nkinematics(phases%length),source = 0) do ph = 1,phases%length phase => phases%get(ph) kinematics => phase%get('kinematics',defaultVal=emptyList) phase_Nkinematics(ph) = kinematics%length enddo - - allocate(phase_kinematics(maxval(phase_Nkinematics),phases%length), source = KINEMATICS_undefined_ID) + + allocate(phase_kinematics(maxval(phase_Nkinematics),phases%length), source = KINEMATICS_undefined_ID) if(maxval(phase_Nkinematics) /= 0) then where(kinematics_cleavage_opening_init(maxval(phase_Nkinematics))) phase_kinematics = KINEMATICS_cleavage_opening_ID where(kinematics_slipplane_opening_init(maxval(phase_Nkinematics))) phase_kinematics = KINEMATICS_slipplane_opening_ID - endif + endif end subroutine damage_init @@ -167,7 +167,7 @@ module subroutine constitutive_damage_getRateAndItsTangents(phiDot, dPhiDot_dPhi ip, & !< integration point number el !< element number real(pReal), intent(in) :: & - phi !< damage parameter + phi !< damage parameter real(pReal), intent(inout) :: & phiDot, & dPhiDot_dPhi @@ -183,7 +183,7 @@ module subroutine constitutive_damage_getRateAndItsTangents(phiDot, dPhiDot_dPhi phiDot = 0.0_pReal dPhiDot_dPhi = 0.0_pReal - + do grain = 1, homogenization_Nconstituents(material_homogenizationAt(el)) phase = material_phaseAt(grain,el) constituent = material_phasememberAt(grain,ip,el) @@ -217,32 +217,35 @@ end subroutine constitutive_damage_getRateAndItsTangents !---------------------------------------------------------------------------------------------- !< @brief writes damage sources results to HDF5 output file !---------------------------------------------------------------------------------------------- -module subroutine damage_results +module subroutine damage_results(group,ph) - integer :: p,i - character(len=pStringLen) :: group + character(len=*), intent(in) :: group + integer, intent(in) :: ph - do p = 1, size(material_name_phase) + integer :: so - sourceLoop: do i = 1, phase_Nsources(p) - group = trim('current/phase')//'/'//trim(material_name_phase(p)) - group = trim(group)//'/sources' - call results_closeGroup(results_addGroup(group)) + sourceLoop: do so = 1, phase_Nsources(ph) - sourceType: select case (phase_source(i,p)) + if (phase_source(so,ph) /= SOURCE_UNDEFINED_ID) & + call results_closeGroup(results_addGroup(group//'sources/')) ! should be 'damage' - case (SOURCE_damage_anisoBrittle_ID) sourceType - call source_damage_anisoBrittle_results(p,group) - case (SOURCE_damage_anisoDuctile_ID) sourceType - call source_damage_anisoDuctile_results(p,group) - case (SOURCE_damage_isoBrittle_ID) sourceType - call source_damage_isoBrittle_results(p,group) - case (SOURCE_damage_isoDuctile_ID) sourceType - call source_damage_isoDuctile_results(p,group) - end select sourceType + sourceType: select case (phase_source(so,ph)) - enddo SourceLoop - enddo + case (SOURCE_damage_anisoBrittle_ID) sourceType + call source_damage_anisoBrittle_results(ph,group//'sources/') + + case (SOURCE_damage_anisoDuctile_ID) sourceType + call source_damage_anisoDuctile_results(ph,group//'sources/') + + case (SOURCE_damage_isoBrittle_ID) sourceType + call source_damage_isoBrittle_results(ph,group//'sources/') + + case (SOURCE_damage_isoDuctile_ID) sourceType + call source_damage_isoDuctile_results(ph,group//'sources/') + + end select sourceType + + enddo SourceLoop end subroutine damage_results diff --git a/src/constitutive_mech.f90 b/src/constitutive_mech.f90 index 2a6bf97eb..c48c59ec9 100644 --- a/src/constitutive_mech.f90 +++ b/src/constitutive_mech.f90 @@ -3,6 +3,19 @@ !---------------------------------------------------------------------------------------------------- submodule(constitutive) constitutive_mech + enum, bind(c); enumerator :: & + ELASTICITY_UNDEFINED_ID, & + ELASTICITY_HOOKE_ID, & + STIFFNESS_DEGRADATION_UNDEFINED_ID, & + STIFFNESS_DEGRADATION_DAMAGE_ID + end enum + + integer(kind(ELASTICITY_undefined_ID)), dimension(:), allocatable :: & + phase_elasticity !< elasticity of each phase + integer(kind(SOURCE_undefined_ID)), dimension(:,:), allocatable :: & + phase_stiffnessDegradation !< active stiffness degradation mechanisms of each phase + + interface module function plastic_none_init() result(myPlasticity) @@ -127,6 +140,66 @@ submodule(constitutive) constitutive_mech el !< current element number end subroutine plastic_nonlocal_LpAndItsTangent + module subroutine plastic_isotropic_dotState(Mp,instance,of) + real(pReal), dimension(3,3), intent(in) :: & + Mp !< Mandel stress + integer, intent(in) :: & + instance, & + of + end subroutine plastic_isotropic_dotState + + module subroutine plastic_phenopowerlaw_dotState(Mp,instance,of) + real(pReal), dimension(3,3), intent(in) :: & + Mp !< Mandel stress + integer, intent(in) :: & + instance, & + of + end subroutine plastic_phenopowerlaw_dotState + + module subroutine plastic_kinehardening_dotState(Mp,instance,of) + real(pReal), dimension(3,3), intent(in) :: & + Mp !< Mandel stress + integer, intent(in) :: & + instance, & + of + end subroutine plastic_kinehardening_dotState + + module subroutine plastic_dislotwin_dotState(Mp,T,instance,of) + real(pReal), dimension(3,3), intent(in) :: & + Mp !< Mandel stress + real(pReal), intent(in) :: & + T + integer, intent(in) :: & + instance, & + of + end subroutine plastic_dislotwin_dotState + + module subroutine plastic_disloTungsten_dotState(Mp,T,instance,of) + real(pReal), dimension(3,3), intent(in) :: & + Mp !< Mandel stress + real(pReal), intent(in) :: & + T + integer, intent(in) :: & + instance, & + of + end subroutine plastic_disloTungsten_dotState + + module subroutine plastic_nonlocal_dotState(Mp, F, Temperature,timestep, & + instance,of,ip,el) + real(pReal), dimension(3,3), intent(in) :: & + Mp !< MandelStress + real(pReal), dimension(3,3,homogenization_maxNconstituents,discretization_nIPs,discretization_Nelems), intent(in) :: & + F !< deformation gradient + real(pReal), intent(in) :: & + Temperature, & !< temperature + timestep !< substepped crystallite time increment + integer, intent(in) :: & + instance, & + of, & + ip, & !< current integration point + el !< current element number + end subroutine plastic_nonlocal_dotState + module subroutine plastic_dislotwin_dependentState(T,instance,of) integer, intent(in) :: & @@ -142,10 +215,9 @@ submodule(constitutive) constitutive_mech of end subroutine plastic_dislotungsten_dependentState - module subroutine plastic_nonlocal_dependentState(F, Fp, instance, of, ip, el) + module subroutine plastic_nonlocal_dependentState(F, instance, of, ip, el) real(pReal), dimension(3,3), intent(in) :: & - F, & !< deformation gradient - Fp !< plastic deformation gradient + F !< deformation gradient integer, intent(in) :: & instance, & of, & @@ -153,6 +225,24 @@ submodule(constitutive) constitutive_mech el !< current element number end subroutine plastic_nonlocal_dependentState + module subroutine plastic_kinehardening_deltaState(Mp,instance,of) + real(pReal), dimension(3,3), intent(in) :: & + Mp !< Mandel stress + integer, intent(in) :: & + instance, & + of + end subroutine plastic_kinehardening_deltaState + + module subroutine plastic_nonlocal_deltaState(Mp,instance,of,ip,el) + real(pReal), dimension(3,3), intent(in) :: & + Mp + integer, intent(in) :: & + instance, & + of, & + ip, & + el + end subroutine plastic_nonlocal_deltaState + module subroutine plastic_isotropic_results(instance,group) integer, intent(in) :: instance character(len=*), intent(in) :: group @@ -183,9 +273,24 @@ submodule(constitutive) constitutive_mech character(len=*), intent(in) :: group end subroutine plastic_nonlocal_results + module function plastic_dislotwin_homogenizedC(co,ip,el) result(homogenizedC) + real(pReal), dimension(6,6) :: & + homogenizedC + integer, intent(in) :: & + co, & !< component-ID of integration point + ip, & !< integration point + el !< element + end function plastic_dislotwin_homogenizedC + end interface + type :: tOutput !< new requested output (per phase) + character(len=pStringLen), allocatable, dimension(:) :: & + label + end type tOutput + type(tOutput), allocatable, dimension(:) :: output_constituent + procedure(integrateStateFPI), pointer :: integrateState contains @@ -197,9 +302,10 @@ contains module subroutine mech_init integer :: & - p, & + ph, & stiffDegradationCtr class(tNode), pointer :: & + num_crystallite, & phases, & phase, & mech, & @@ -214,31 +320,37 @@ module subroutine mech_init allocate(phase_elasticity(phases%length), source = ELASTICITY_undefined_ID) allocate(phase_elasticityInstance(phases%length), source = 0) allocate(phase_NstiffnessDegradations(phases%length),source=0) + allocate(output_constituent(phases%length)) - do p = 1, phases%length - phase => phases%get(p) + do ph = 1, phases%length + phase => phases%get(ph) mech => phase%get('mechanics') +#if defined(__GFORTRAN__) + output_constituent(ph)%label = output_asStrings(mech) +#else + output_constituent(ph)%label = mech%get_asStrings('output',defaultVal=emptyStringArray) +#endif elastic => mech%get('elasticity') if(elastic%get_asString('type') == 'hooke') then - phase_elasticity(p) = ELASTICITY_HOOKE_ID + phase_elasticity(ph) = ELASTICITY_HOOKE_ID else call IO_error(200,ext_msg=elastic%get_asString('type')) endif stiffDegradation => mech%get('stiffness_degradation',defaultVal=emptyList) ! check for stiffness degradation mechanisms - phase_NstiffnessDegradations(p) = stiffDegradation%length + phase_NstiffnessDegradations(ph) = stiffDegradation%length enddo allocate(phase_stiffnessDegradation(maxval(phase_NstiffnessDegradations),phases%length), & source=STIFFNESS_DEGRADATION_undefined_ID) if(maxVal(phase_NstiffnessDegradations)/=0) then - do p = 1, phases%length - phase => phases%get(p) + do ph = 1, phases%length + phase => phases%get(ph) mech => phase%get('mechanics') stiffDegradation => mech%get('stiffness_degradation',defaultVal=emptyList) do stiffDegradationCtr = 1, stiffDegradation%length if(stiffDegradation%get_asString(stiffDegradationCtr) == 'damage') & - phase_stiffnessDegradation(stiffDegradationCtr,p) = STIFFNESS_DEGRADATION_damage_ID + phase_stiffnessDegradation(stiffDegradationCtr,ph) = STIFFNESS_DEGRADATION_damage_ID enddo enddo endif @@ -258,18 +370,42 @@ module subroutine mech_init where(plastic_dislotungsten_init()) phase_plasticity = PLASTICITY_DISLOTUNGSTEN_ID where(plastic_nonlocal_init()) phase_plasticity = PLASTICITY_NONLOCAL_ID - do p = 1, phases%length - phase_elasticityInstance(p) = count(phase_elasticity(1:p) == phase_elasticity(p)) - phase_plasticityInstance(p) = count(phase_plasticity(1:p) == phase_plasticity(p)) + do ph = 1, phases%length + phase_elasticityInstance(ph) = count(phase_elasticity(1:ph) == phase_elasticity(ph)) + phase_plasticityInstance(ph) = count(phase_plasticity(1:ph) == phase_plasticity(ph)) enddo + num_crystallite => config_numerics%get('crystallite',defaultVal=emptyDict) + + select case(num_crystallite%get_asString('integrator',defaultVal='FPI')) + + case('FPI') + integrateState => integrateStateFPI + + case('Euler') + integrateState => integrateStateEuler + + case('AdaptiveEuler') + integrateState => integrateStateAdaptiveEuler + + case('RK4') + integrateState => integrateStateRK4 + + case('RKCK45') + integrateState => integrateStateRKCK45 + + case default + call IO_error(301,ext_msg='integrator') + + end select + end subroutine mech_init !-------------------------------------------------------------------------------------------------- !> @brief checks if a plastic module is active or not !-------------------------------------------------------------------------------------------------- -module function plastic_active(plastic_label) result(active_plastic) +function plastic_active(plastic_label) result(active_plastic) character(len=*), intent(in) :: plastic_label !< type of plasticity model logical, dimension(:), allocatable :: active_plastic @@ -279,15 +415,15 @@ module function plastic_active(plastic_label) result(active_plastic) phase, & mech, & pl - integer :: p + integer :: ph phases => config_material%get('phase') allocate(active_plastic(phases%length), source = .false. ) - do p = 1, phases%length - phase => phases%get(p) + do ph = 1, phases%length + phase => phases%get(ph) mech => phase%get('mechanics') pl => mech%get('plasticity') - if(pl%get_asString('type') == plastic_label) active_plastic(p) = .true. + if(pl%get_asString('type') == plastic_label) active_plastic(ph) = .true. enddo end function plastic_active @@ -298,10 +434,10 @@ end function plastic_active !> the elastic and intermediate deformation gradients using Hooke's law !-------------------------------------------------------------------------------------------------- module subroutine constitutive_hooke_SandItsTangents(S, dS_dFe, dS_dFi, & - Fe, Fi, ipc, ip, el) + Fe, Fi, co, ip, el) integer, intent(in) :: & - ipc, & !< component-ID of integration point + co, & !< component-ID of integration point ip, & !< integration point el !< element real(pReal), intent(in), dimension(3,3) :: & @@ -321,12 +457,12 @@ module subroutine constitutive_hooke_SandItsTangents(S, dS_dFe, dS_dFi, & i, j ho = material_homogenizationAt(el) - C = math_66toSym3333(constitutive_homogenizedC(ipc,ip,el)) + C = math_66toSym3333(constitutive_homogenizedC(co,ip,el)) - DegradationLoop: do d = 1, phase_NstiffnessDegradations(material_phaseAt(ipc,el)) - degradationType: select case(phase_stiffnessDegradation(d,material_phaseAt(ipc,el))) + DegradationLoop: do d = 1, phase_NstiffnessDegradations(material_phaseAt(co,el)) + degradationType: select case(phase_stiffnessDegradation(d,material_phaseAt(co,el))) case (STIFFNESS_DEGRADATION_damage_ID) degradationType - C = C * damage(ho)%p(damageMapping(ho)%p(ip,el))**2 + C = C * damage(ho)%p(material_homogenizationMemberAt(ip,el))**2 end select degradationType enddo DegradationLoop @@ -344,15 +480,14 @@ end subroutine constitutive_hooke_SandItsTangents !-------------------------------------------------------------------------------------------------- !> @brief calls microstructure function of the different plasticity constitutive models !-------------------------------------------------------------------------------------------------- -module subroutine constitutive_plastic_dependentState(F, Fp, ipc, ip, el) +module subroutine constitutive_plastic_dependentState(F, co, ip, el) integer, intent(in) :: & - ipc, & !< component-ID of integration point + co, & !< component-ID of integration point ip, & !< integration point el !< element real(pReal), intent(in), dimension(3,3) :: & - F, & !< elastic deformation gradient - Fp !< plastic deformation gradient + F !< deformation gradient integer :: & ho, & !< homogenization @@ -360,17 +495,17 @@ module subroutine constitutive_plastic_dependentState(F, Fp, ipc, ip, el) instance, of ho = material_homogenizationAt(el) - tme = thermalMapping(ho)%p(ip,el) - of = material_phasememberAt(ipc,ip,el) - instance = phase_plasticityInstance(material_phaseAt(ipc,el)) + tme = material_homogenizationMemberAt(ip,el) + of = material_phasememberAt(co,ip,el) + instance = phase_plasticityInstance(material_phaseAt(co,el)) - plasticityType: select case (phase_plasticity(material_phaseAt(ipc,el))) + plasticityType: select case (phase_plasticity(material_phaseAt(co,el))) case (PLASTICITY_DISLOTWIN_ID) plasticityType call plastic_dislotwin_dependentState(temperature(ho)%p(tme),instance,of) case (PLASTICITY_DISLOTUNGSTEN_ID) plasticityType call plastic_dislotungsten_dependentState(instance,of) case (PLASTICITY_NONLOCAL_ID) plasticityType - call plastic_nonlocal_dependentState (F,Fp,instance,of,ip,el) + call plastic_nonlocal_dependentState (F,instance,of,ip,el) end select plasticityType end subroutine constitutive_plastic_dependentState @@ -382,9 +517,9 @@ end subroutine constitutive_plastic_dependentState ! Mp in, dLp_dMp out !-------------------------------------------------------------------------------------------------- module subroutine constitutive_plastic_LpAndItsTangents(Lp, dLp_dS, dLp_dFi, & - S, Fi, ipc, ip, el) + S, Fi, co, ip, el) integer, intent(in) :: & - ipc, & !< component-ID of integration point + co, & !< component-ID of integration point ip, & !< integration point el !< element real(pReal), intent(in), dimension(3,3) :: & @@ -407,13 +542,13 @@ module subroutine constitutive_plastic_LpAndItsTangents(Lp, dLp_dS, dLp_dFi, & i, j, instance, of ho = material_homogenizationAt(el) - tme = thermalMapping(ho)%p(ip,el) + tme = material_homogenizationMemberAt(ip,el) Mp = matmul(matmul(transpose(Fi),Fi),S) - of = material_phasememberAt(ipc,ip,el) - instance = phase_plasticityInstance(material_phaseAt(ipc,el)) + of = material_phasememberAt(co,ip,el) + instance = phase_plasticityInstance(material_phaseAt(co,el)) - plasticityType: select case (phase_plasticity(material_phaseAt(ipc,el))) + plasticityType: select case (phase_plasticity(material_phaseAt(co,el))) case (PLASTICITY_NONE_ID) plasticityType Lp = 0.0_pReal @@ -448,45 +583,1029 @@ module subroutine constitutive_plastic_LpAndItsTangents(Lp, dLp_dS, dLp_dFi, & end subroutine constitutive_plastic_LpAndItsTangents -!-------------------------------------------------------------------------------------------- -!> @brief writes plasticity constitutive results to HDF5 output file -!-------------------------------------------------------------------------------------------- -module subroutine plastic_results +!-------------------------------------------------------------------------------------------------- +!> @brief contains the constitutive equation for calculating the rate of change of microstructure +!-------------------------------------------------------------------------------------------------- +function mech_collectDotState(subdt, co, ip, el,ph,of) result(broken) - integer :: p - character(len=pStringLen) :: group + integer, intent(in) :: & + co, & !< component-ID of integration point + ip, & !< integration point + el, & !< element + ph, & + of + real(pReal), intent(in) :: & + subdt !< timestep + real(pReal), dimension(3,3) :: & + Mp + integer :: & + ho, & !< homogenization + tme, & !< thermal member position + i, & !< counter in source loop + instance + logical :: broken + ho = material_homogenizationAt(el) + tme = material_homogenizationMemberAt(ip,el) + instance = phase_plasticityInstance(ph) - plasticityLoop: do p=1,size(material_name_phase) - group = trim('current/phase')//'/'//trim(material_name_phase(p)) - call results_closeGroup(results_addGroup(group)) + Mp = matmul(matmul(transpose(constitutive_mech_Fi(ph)%data(1:3,1:3,of)),& + constitutive_mech_Fi(ph)%data(1:3,1:3,of)),crystallite_S(1:3,1:3,co,ip,el)) - group = trim(group)//'/plastic' + plasticityType: select case (phase_plasticity(ph)) - call results_closeGroup(results_addGroup(group)) - select case(phase_plasticity(p)) + case (PLASTICITY_ISOTROPIC_ID) plasticityType + call plastic_isotropic_dotState(Mp,instance,of) - case(PLASTICITY_ISOTROPIC_ID) - call plastic_isotropic_results(phase_plasticityInstance(p),group) + case (PLASTICITY_PHENOPOWERLAW_ID) plasticityType + call plastic_phenopowerlaw_dotState(Mp,instance,of) - case(PLASTICITY_PHENOPOWERLAW_ID) - call plastic_phenopowerlaw_results(phase_plasticityInstance(p),group) + case (PLASTICITY_KINEHARDENING_ID) plasticityType + call plastic_kinehardening_dotState(Mp,instance,of) - case(PLASTICITY_KINEHARDENING_ID) - call plastic_kinehardening_results(phase_plasticityInstance(p),group) + case (PLASTICITY_DISLOTWIN_ID) plasticityType + call plastic_dislotwin_dotState(Mp,temperature(ho)%p(tme),instance,of) - case(PLASTICITY_DISLOTWIN_ID) - call plastic_dislotwin_results(phase_plasticityInstance(p),group) + case (PLASTICITY_DISLOTUNGSTEN_ID) plasticityType + call plastic_disloTungsten_dotState(Mp,temperature(ho)%p(tme),instance,of) - case(PLASTICITY_DISLOTUNGSTEN_ID) - call plastic_dislotungsten_results(phase_plasticityInstance(p),group) + case (PLASTICITY_NONLOCAL_ID) plasticityType + call plastic_nonlocal_dotState(Mp,crystallite_partitionedF0,temperature(ho)%p(tme),subdt, & + instance,of,ip,el) + end select plasticityType + broken = any(IEEE_is_NaN(plasticState(ph)%dotState(:,of))) - case(PLASTICITY_NONLOCAL_ID) - call plastic_nonlocal_results(phase_plasticityInstance(p),group) + +end function mech_collectDotState + + +!-------------------------------------------------------------------------------------------------- +!> @brief for constitutive models having an instantaneous change of state +!> will return false if delta state is not needed/supported by the constitutive model +!-------------------------------------------------------------------------------------------------- +function constitutive_deltaState(S, Fi, co, ip, el, ph, of) result(broken) + + integer, intent(in) :: & + co, & !< component-ID of integration point + ip, & !< integration point + el, & !< element + ph, & + of + real(pReal), intent(in), dimension(3,3) :: & + S, & !< 2nd Piola Kirchhoff stress + Fi !< intermediate deformation gradient + real(pReal), dimension(3,3) :: & + Mp + integer :: & + instance, & + myOffset, & + mySize + logical :: & + broken + + Mp = matmul(matmul(transpose(Fi),Fi),S) + instance = phase_plasticityInstance(ph) + + plasticityType: select case (phase_plasticity(ph)) + + case (PLASTICITY_KINEHARDENING_ID) plasticityType + call plastic_kinehardening_deltaState(Mp,instance,of) + broken = any(IEEE_is_NaN(plasticState(ph)%deltaState(:,of))) + + case (PLASTICITY_NONLOCAL_ID) plasticityType + call plastic_nonlocal_deltaState(Mp,instance,of,ip,el) + broken = any(IEEE_is_NaN(plasticState(ph)%deltaState(:,of))) + + case default + broken = .false. + + end select plasticityType + + if(.not. broken) then + select case(phase_plasticity(ph)) + case (PLASTICITY_NONLOCAL_ID,PLASTICITY_KINEHARDENING_ID) + + myOffset = plasticState(ph)%offsetDeltaState + mySize = plasticState(ph)%sizeDeltaState + plasticState(ph)%state(myOffset + 1:myOffset + mySize,of) = & + plasticState(ph)%state(myOffset + 1:myOffset + mySize,of) + plasticState(ph)%deltaState(1:mySize,of) end select + endif - enddo plasticityLoop +end function constitutive_deltaState -end subroutine plastic_results + +module subroutine mech_results(group,ph) + + character(len=*), intent(in) :: group + integer, intent(in) :: ph + + if (phase_plasticity(ph) /= PLASTICITY_NONE_ID) & + call results_closeGroup(results_addGroup(group//'plastic/')) + + select case(phase_plasticity(ph)) + + case(PLASTICITY_ISOTROPIC_ID) + call plastic_isotropic_results(phase_plasticityInstance(ph),group//'plastic/') + + case(PLASTICITY_PHENOPOWERLAW_ID) + call plastic_phenopowerlaw_results(phase_plasticityInstance(ph),group//'plastic/') + + case(PLASTICITY_KINEHARDENING_ID) + call plastic_kinehardening_results(phase_plasticityInstance(ph),group//'plastic/') + + case(PLASTICITY_DISLOTWIN_ID) + call plastic_dislotwin_results(phase_plasticityInstance(ph),group//'plastic/') + + case(PLASTICITY_DISLOTUNGSTEN_ID) + call plastic_dislotungsten_results(phase_plasticityInstance(ph),group//'plastic/') + + case(PLASTICITY_NONLOCAL_ID) + call plastic_nonlocal_results(phase_plasticityInstance(ph),group//'plastic/') + + end select + + call crystallite_results(group,ph) + +end subroutine mech_results + + module subroutine mech_restart_read(fileHandle) + integer(HID_T), intent(in) :: fileHandle + end subroutine mech_restart_read + + +!-------------------------------------------------------------------------------------------------- +!> @brief calculation of stress (P) with time integration based on a residuum in Lp and +!> intermediate acceleration of the Newton-Raphson correction +!-------------------------------------------------------------------------------------------------- +function integrateStress(F,Delta_t,co,ip,el) result(broken) + + real(pReal), dimension(3,3), intent(in) :: F + real(pReal), intent(in) :: Delta_t + integer, intent(in):: el, & ! element index + ip, & ! integration point index + co ! grain index + + real(pReal), dimension(3,3):: Fp_new, & ! plastic deformation gradient at end of timestep + invFp_new, & ! inverse of Fp_new + invFp_current, & ! inverse of Fp_current + Lpguess, & ! current guess for plastic velocity gradient + Lpguess_old, & ! known last good guess for plastic velocity gradient + Lp_constitutive, & ! plastic velocity gradient resulting from constitutive law + residuumLp, & ! current residuum of plastic velocity gradient + residuumLp_old, & ! last residuum of plastic velocity gradient + deltaLp, & ! direction of next guess + Fi_new, & ! gradient of intermediate deformation stages + invFi_new, & + invFi_current, & ! inverse of Fi_current + Liguess, & ! current guess for intermediate velocity gradient + Liguess_old, & ! known last good guess for intermediate velocity gradient + Li_constitutive, & ! intermediate velocity gradient resulting from constitutive law + residuumLi, & ! current residuum of intermediate velocity gradient + residuumLi_old, & ! last residuum of intermediate velocity gradient + deltaLi, & ! direction of next guess + Fe, & ! elastic deformation gradient + S, & ! 2nd Piola-Kirchhoff Stress in plastic (lattice) configuration + A, & + B, & + temp_33 + real(pReal), dimension(9) :: temp_9 ! needed for matrix inversion by LAPACK + integer, dimension(9) :: devNull_9 ! needed for matrix inversion by LAPACK + real(pReal), dimension(9,9) :: dRLp_dLp, & ! partial derivative of residuum (Jacobian for Newton-Raphson scheme) + dRLi_dLi ! partial derivative of residuumI (Jacobian for Newton-Raphson scheme) + real(pReal), dimension(3,3,3,3):: dS_dFe, & ! partial derivative of 2nd Piola-Kirchhoff stress + dS_dFi, & + dFe_dLp, & ! partial derivative of elastic deformation gradient + dFe_dLi, & + dFi_dLi, & + dLp_dFi, & + dLi_dFi, & + dLp_dS, & + dLi_dS + real(pReal) steplengthLp, & + steplengthLi, & + atol_Lp, & + atol_Li, & + devNull + integer NiterationStressLp, & ! number of stress integrations + NiterationStressLi, & ! number of inner stress integrations + ierr, & ! error indicator for LAPACK + o, & + p, & + m, & + ph, & + me, & + jacoCounterLp, & + jacoCounterLi ! counters to check for Jacobian update + logical :: error,broken + + broken = .true. + + call constitutive_plastic_dependentState(crystallite_F(1:3,1:3,co,ip,el),co,ip,el) + + ph = material_phaseAt(co,el) + me = material_phaseMemberAt(co,ip,el) + + Lpguess = crystallite_Lp(1:3,1:3,co,ip,el) ! take as first guess + Liguess = constitutive_mech_Li(ph)%data(1:3,1:3,me) ! take as first guess + + call math_invert33(invFp_current,devNull,error,crystallite_subFp0(1:3,1:3,co,ip,el)) + if (error) return ! error + call math_invert33(invFi_current,devNull,error,crystallite_subFi0(1:3,1:3,co,ip,el)) + if (error) return ! error + + A = matmul(F,invFp_current) ! intermediate tensor needed later to calculate dFe_dLp + + jacoCounterLi = 0 + steplengthLi = 1.0_pReal + residuumLi_old = 0.0_pReal + Liguess_old = Liguess + + NiterationStressLi = 0 + LiLoop: do + NiterationStressLi = NiterationStressLi + 1 + if (NiterationStressLi>num%nStress) return ! error + + invFi_new = matmul(invFi_current,math_I3 - Delta_t*Liguess) + Fi_new = math_inv33(invFi_new) + + jacoCounterLp = 0 + steplengthLp = 1.0_pReal + residuumLp_old = 0.0_pReal + Lpguess_old = Lpguess + + NiterationStressLp = 0 + LpLoop: do + NiterationStressLp = NiterationStressLp + 1 + if (NiterationStressLp>num%nStress) return ! error + + B = math_I3 - Delta_t*Lpguess + Fe = matmul(matmul(A,B), invFi_new) + call constitutive_hooke_SandItsTangents(S, dS_dFe, dS_dFi, & + Fe, Fi_new, co, ip, el) + + call constitutive_plastic_LpAndItsTangents(Lp_constitutive, dLp_dS, dLp_dFi, & + S, Fi_new, co, ip, el) + + !* update current residuum and check for convergence of loop + atol_Lp = max(num%rtol_crystalliteStress * max(norm2(Lpguess),norm2(Lp_constitutive)), & ! absolute tolerance from largest acceptable relative error + num%atol_crystalliteStress) ! minimum lower cutoff + residuumLp = Lpguess - Lp_constitutive + + if (any(IEEE_is_NaN(residuumLp))) then + return ! error + elseif (norm2(residuumLp) < atol_Lp) then ! converged if below absolute tolerance + exit LpLoop + elseif (NiterationStressLp == 1 .or. norm2(residuumLp) < norm2(residuumLp_old)) then ! not converged, but improved norm of residuum (always proceed in first iteration)... + residuumLp_old = residuumLp ! ...remember old values and... + Lpguess_old = Lpguess + steplengthLp = 1.0_pReal ! ...proceed with normal step length (calculate new search direction) + else ! not converged and residuum not improved... + steplengthLp = num%subStepSizeLp * steplengthLp ! ...try with smaller step length in same direction + Lpguess = Lpguess_old & + + deltaLp * stepLengthLp + cycle LpLoop + endif + + calculateJacobiLi: if (mod(jacoCounterLp, num%iJacoLpresiduum) == 0) then + jacoCounterLp = jacoCounterLp + 1 + + do o=1,3; do p=1,3 + dFe_dLp(o,1:3,p,1:3) = - Delta_t * A(o,p)*transpose(invFi_new) ! dFe_dLp(i,j,k,l) = -Delta_t * A(i,k) invFi(l,j) + enddo; enddo + dRLp_dLp = math_eye(9) & + - math_3333to99(math_mul3333xx3333(math_mul3333xx3333(dLp_dS,dS_dFe),dFe_dLp)) + temp_9 = math_33to9(residuumLp) + call dgesv(9,1,dRLp_dLp,9,devNull_9,temp_9,9,ierr) ! solve dRLp/dLp * delta Lp = -res for delta Lp + if (ierr /= 0) return ! error + deltaLp = - math_9to33(temp_9) + endif calculateJacobiLi + + Lpguess = Lpguess & + + deltaLp * steplengthLp + enddo LpLoop + + call constitutive_LiAndItsTangents(Li_constitutive, dLi_dS, dLi_dFi, & + S, Fi_new, co, ip, el) + + !* update current residuum and check for convergence of loop + atol_Li = max(num%rtol_crystalliteStress * max(norm2(Liguess),norm2(Li_constitutive)), & ! absolute tolerance from largest acceptable relative error + num%atol_crystalliteStress) ! minimum lower cutoff + residuumLi = Liguess - Li_constitutive + if (any(IEEE_is_NaN(residuumLi))) then + return ! error + elseif (norm2(residuumLi) < atol_Li) then ! converged if below absolute tolerance + exit LiLoop + elseif (NiterationStressLi == 1 .or. norm2(residuumLi) < norm2(residuumLi_old)) then ! not converged, but improved norm of residuum (always proceed in first iteration)... + residuumLi_old = residuumLi ! ...remember old values and... + Liguess_old = Liguess + steplengthLi = 1.0_pReal ! ...proceed with normal step length (calculate new search direction) + else ! not converged and residuum not improved... + steplengthLi = num%subStepSizeLi * steplengthLi ! ...try with smaller step length in same direction + Liguess = Liguess_old & + + deltaLi * steplengthLi + cycle LiLoop + endif + + calculateJacobiLp: if (mod(jacoCounterLi, num%iJacoLpresiduum) == 0) then + jacoCounterLi = jacoCounterLi + 1 + + temp_33 = matmul(matmul(A,B),invFi_current) + do o=1,3; do p=1,3 + dFe_dLi(1:3,o,1:3,p) = -Delta_t*math_I3(o,p)*temp_33 ! dFe_dLp(i,j,k,l) = -Delta_t * A(i,k) invFi(l,j) + dFi_dLi(1:3,o,1:3,p) = -Delta_t*math_I3(o,p)*invFi_current + enddo; enddo + do o=1,3; do p=1,3 + dFi_dLi(1:3,1:3,o,p) = matmul(matmul(Fi_new,dFi_dLi(1:3,1:3,o,p)),Fi_new) + enddo; enddo + dRLi_dLi = math_eye(9) & + - math_3333to99(math_mul3333xx3333(dLi_dS, math_mul3333xx3333(dS_dFe, dFe_dLi) & + + math_mul3333xx3333(dS_dFi, dFi_dLi))) & + - math_3333to99(math_mul3333xx3333(dLi_dFi, dFi_dLi)) + temp_9 = math_33to9(residuumLi) + call dgesv(9,1,dRLi_dLi,9,devNull_9,temp_9,9,ierr) ! solve dRLi/dLp * delta Li = -res for delta Li + if (ierr /= 0) return ! error + deltaLi = - math_9to33(temp_9) + endif calculateJacobiLp + + Liguess = Liguess & + + deltaLi * steplengthLi + enddo LiLoop + + invFp_new = matmul(invFp_current,B) + call math_invert33(Fp_new,devNull,error,invFp_new) + if (error) return ! error + + crystallite_P (1:3,1:3,co,ip,el) = matmul(matmul(F,invFp_new),matmul(S,transpose(invFp_new))) + crystallite_S (1:3,1:3,co,ip,el) = S + crystallite_Lp (1:3,1:3,co,ip,el) = Lpguess + constitutive_mech_Li(ph)%data(1:3,1:3,me) = Liguess + constitutive_mech_Fp(ph)%data(1:3,1:3,me) = Fp_new / math_det33(Fp_new)**(1.0_pReal/3.0_pReal) ! regularize + constitutive_mech_Fi(ph)%data(1:3,1:3,me) = Fi_new + crystallite_Fe (1:3,1:3,co,ip,el) = matmul(matmul(F,invFp_new),invFi_new) + broken = .false. + +end function integrateStress + + +!-------------------------------------------------------------------------------------------------- +!> @brief integrate stress, state with adaptive 1st order explicit Euler method +!> using Fixed Point Iteration to adapt the stepsize +!-------------------------------------------------------------------------------------------------- +function integrateStateFPI(F_0,F,Delta_t,co,ip,el) result(broken) + + real(pReal), intent(in),dimension(3,3) :: F_0,F + real(pReal), intent(in) :: Delta_t + integer, intent(in) :: & + el, & !< element index in element loop + ip, & !< integration point index in ip loop + co !< grain index in grain loop + logical :: & + broken + + integer :: & + NiterationState, & !< number of iterations in state loop + ph, & + me, & + sizeDotState + real(pReal) :: & + zeta + real(pReal), dimension(constitutive_plasticity_maxSizeDotState) :: & + r ! state residuum + real(pReal), dimension(constitutive_plasticity_maxSizeDotState,2) :: & + dotState + + + ph = material_phaseAt(co,el) + me = material_phaseMemberAt(co,ip,el) + + broken = mech_collectDotState(Delta_t, co,ip,el,ph,me) + if(broken) return + + sizeDotState = plasticState(ph)%sizeDotState + plasticState(ph)%state(1:sizeDotState,me) = plasticState(ph)%subState0(1:sizeDotState,me) & + + plasticState(ph)%dotState (1:sizeDotState,me) * Delta_t + dotState(1:sizeDotState,2) = 0.0_pReal + + iteration: do NiterationState = 1, num%nState + + if(nIterationState > 1) dotState(1:sizeDotState,2) = dotState(1:sizeDotState,1) + dotState(1:sizeDotState,1) = plasticState(ph)%dotState(:,me) + + broken = integrateStress(F,Delta_t,co,ip,el) + if(broken) exit iteration + + broken = mech_collectDotState(Delta_t, co,ip,el,ph,me) + if(broken) exit iteration + + zeta = damper(plasticState(ph)%dotState(:,me),dotState(1:sizeDotState,1),& + dotState(1:sizeDotState,2)) + plasticState(ph)%dotState(:,me) = plasticState(ph)%dotState(:,me) * zeta & + + dotState(1:sizeDotState,1) * (1.0_pReal - zeta) + r(1:sizeDotState) = plasticState(ph)%state (1:sizeDotState,me) & + - plasticState(ph)%subState0(1:sizeDotState,me) & + - plasticState(ph)%dotState (1:sizeDotState,me) * Delta_t + plasticState(ph)%state(1:sizeDotState,me) = plasticState(ph)%state(1:sizeDotState,me) & + - r(1:sizeDotState) + if (converged(r(1:sizeDotState),plasticState(ph)%state(1:sizeDotState,me),plasticState(ph)%atol(1:sizeDotState))) then + broken = constitutive_deltaState(crystallite_S(1:3,1:3,co,ip,el), & + constitutive_mech_Fi(ph)%data(1:3,1:3,me),co,ip,el,ph,me) + exit iteration + endif + + enddo iteration + + + contains + + !-------------------------------------------------------------------------------------------------- + !> @brief calculate the damping for correction of state and dot state + !-------------------------------------------------------------------------------------------------- + real(pReal) pure function damper(current,previous,previous2) + + real(pReal), dimension(:), intent(in) ::& + current, previous, previous2 + + real(pReal) :: dot_prod12, dot_prod22 + + dot_prod12 = dot_product(current - previous, previous - previous2) + dot_prod22 = dot_product(previous - previous2, previous - previous2) + if ((dot_product(current,previous) < 0.0_pReal .or. dot_prod12 < 0.0_pReal) .and. dot_prod22 > 0.0_pReal) then + damper = 0.75_pReal + 0.25_pReal * tanh(2.0_pReal + 4.0_pReal * dot_prod12 / dot_prod22) + else + damper = 1.0_pReal + endif + + end function damper + +end function integrateStateFPI + + +!-------------------------------------------------------------------------------------------------- +!> @brief integrate state with 1st order explicit Euler method +!-------------------------------------------------------------------------------------------------- +function integrateStateEuler(F_0,F,Delta_t,co,ip,el) result(broken) + + real(pReal), intent(in),dimension(3,3) :: F_0,F + real(pReal), intent(in) :: Delta_t + integer, intent(in) :: & + el, & !< element index in element loop + ip, & !< integration point index in ip loop + co !< grain index in grain loop + logical :: & + broken + + integer :: & + ph, & + me, & + sizeDotState + + + ph = material_phaseAt(co,el) + me = material_phaseMemberAt(co,ip,el) + + broken = mech_collectDotState(Delta_t, co,ip,el,ph,me) + if(broken) return + + sizeDotState = plasticState(ph)%sizeDotState + plasticState(ph)%state(1:sizeDotState,me) = plasticState(ph)%subState0(1:sizeDotState,me) & + + plasticState(ph)%dotState (1:sizeDotState,me) * Delta_t + + broken = constitutive_deltaState(crystallite_S(1:3,1:3,co,ip,el), & + constitutive_mech_Fi(ph)%data(1:3,1:3,me),co,ip,el,ph,me) + if(broken) return + + broken = integrateStress(F,Delta_t,co,ip,el) + +end function integrateStateEuler + + +!-------------------------------------------------------------------------------------------------- +!> @brief integrate stress, state with 1st order Euler method with adaptive step size +!-------------------------------------------------------------------------------------------------- +function integrateStateAdaptiveEuler(F_0,F,Delta_t,co,ip,el) result(broken) + + real(pReal), intent(in),dimension(3,3) :: F_0,F + real(pReal), intent(in) :: Delta_t + integer, intent(in) :: & + el, & !< element index in element loop + ip, & !< integration point index in ip loop + co !< grain index in grain loop + logical :: & + broken + + integer :: & + ph, & + me, & + sizeDotState + real(pReal), dimension(constitutive_plasticity_maxSizeDotState) :: residuum_plastic + + + ph = material_phaseAt(co,el) + me = material_phaseMemberAt(co,ip,el) + + broken = mech_collectDotState(Delta_t, co,ip,el,ph,me) + if(broken) return + + sizeDotState = plasticState(ph)%sizeDotState + + residuum_plastic(1:sizeDotState) = - plasticState(ph)%dotstate(1:sizeDotState,me) * 0.5_pReal * Delta_t + plasticState(ph)%state(1:sizeDotState,me) = plasticState(ph)%subState0(1:sizeDotState,me) & + + plasticState(ph)%dotstate(1:sizeDotState,me) * Delta_t + + broken = constitutive_deltaState(crystallite_S(1:3,1:3,co,ip,el), & + constitutive_mech_Fi(ph)%data(1:3,1:3,me),co,ip,el,ph,me) + if(broken) return + + broken = integrateStress(F,Delta_t,co,ip,el) + if(broken) return + + broken = mech_collectDotState(Delta_t, co,ip,el,ph,me) + if(broken) return + + broken = .not. converged(residuum_plastic(1:sizeDotState) + 0.5_pReal * plasticState(ph)%dotState(:,me) * Delta_t, & + plasticState(ph)%state(1:sizeDotState,me), & + plasticState(ph)%atol(1:sizeDotState)) + +end function integrateStateAdaptiveEuler + + +!--------------------------------------------------------------------------------------------------- +!> @brief Integrate state (including stress integration) with the classic Runge Kutta method +!--------------------------------------------------------------------------------------------------- +function integrateStateRK4(F_0,F,Delta_t,co,ip,el) result(broken) + + real(pReal), intent(in),dimension(3,3) :: F_0,F + real(pReal), intent(in) :: Delta_t + integer, intent(in) :: co,ip,el + logical :: broken + + real(pReal), dimension(3,3), parameter :: & + A = reshape([& + 0.5_pReal, 0.0_pReal, 0.0_pReal, & + 0.0_pReal, 0.5_pReal, 0.0_pReal, & + 0.0_pReal, 0.0_pReal, 1.0_pReal],& + shape(A)) + real(pReal), dimension(3), parameter :: & + C = [0.5_pReal, 0.5_pReal, 1.0_pReal] + real(pReal), dimension(4), parameter :: & + B = [1.0_pReal/6.0_pReal, 1.0_pReal/3.0_pReal, 1.0_pReal/3.0_pReal, 1.0_pReal/6.0_pReal] + + + broken = integrateStateRK(F_0,F,Delta_t,co,ip,el,A,B,C) + +end function integrateStateRK4 + + +!--------------------------------------------------------------------------------------------------- +!> @brief Integrate state (including stress integration) with the Cash-Carp method +!--------------------------------------------------------------------------------------------------- +function integrateStateRKCK45(F_0,F,Delta_t,co,ip,el) result(broken) + + real(pReal), intent(in),dimension(3,3) :: F_0,F + real(pReal), intent(in) :: Delta_t + integer, intent(in) :: co,ip,el + logical :: broken + + real(pReal), dimension(5,5), parameter :: & + A = reshape([& + 1._pReal/5._pReal, .0_pReal, .0_pReal, .0_pReal, .0_pReal, & + 3._pReal/40._pReal, 9._pReal/40._pReal, .0_pReal, .0_pReal, .0_pReal, & + 3_pReal/10._pReal, -9._pReal/10._pReal, 6._pReal/5._pReal, .0_pReal, .0_pReal, & + -11._pReal/54._pReal, 5._pReal/2._pReal, -70.0_pReal/27.0_pReal, 35.0_pReal/27.0_pReal, .0_pReal, & + 1631._pReal/55296._pReal,175._pReal/512._pReal,575._pReal/13824._pReal,44275._pReal/110592._pReal,253._pReal/4096._pReal],& + shape(A)) + real(pReal), dimension(5), parameter :: & + C = [0.2_pReal, 0.3_pReal, 0.6_pReal, 1.0_pReal, 0.875_pReal] + real(pReal), dimension(6), parameter :: & + B = & + [37.0_pReal/378.0_pReal, .0_pReal, 250.0_pReal/621.0_pReal, & + 125.0_pReal/594.0_pReal, .0_pReal, 512.0_pReal/1771.0_pReal], & + DB = B - & + [2825.0_pReal/27648.0_pReal, .0_pReal, 18575.0_pReal/48384.0_pReal,& + 13525.0_pReal/55296.0_pReal, 277.0_pReal/14336.0_pReal, 1._pReal/4._pReal] + + + broken = integrateStateRK(F_0,F,Delta_t,co,ip,el,A,B,C,DB) + +end function integrateStateRKCK45 + + +!-------------------------------------------------------------------------------------------------- +!> @brief Integrate state (including stress integration) with an explicit Runge-Kutta method or an +!! embedded explicit Runge-Kutta method +!-------------------------------------------------------------------------------------------------- +function integrateStateRK(F_0,F,Delta_t,co,ip,el,A,B,C,DB) result(broken) + + real(pReal), intent(in),dimension(3,3) :: F_0,F + real(pReal), intent(in) :: Delta_t + real(pReal), dimension(:,:), intent(in) :: A + real(pReal), dimension(:), intent(in) :: B, C + real(pReal), dimension(:), intent(in), optional :: DB + integer, intent(in) :: & + el, & !< element index in element loop + ip, & !< integration point index in ip loop + co !< grain index in grain loop + logical :: broken + + integer :: & + stage, & ! stage index in integration stage loop + n, & + ph, & + me, & + sizeDotState + real(pReal), dimension(constitutive_plasticity_maxSizeDotState,size(B)) :: plastic_RKdotState + + + ph = material_phaseAt(co,el) + me = material_phaseMemberAt(co,ip,el) + + broken = mech_collectDotState(Delta_t,co,ip,el,ph,me) + if(broken) return + + sizeDotState = plasticState(ph)%sizeDotState + + do stage = 1, size(A,1) + + plastic_RKdotState(1:sizeDotState,stage) = plasticState(ph)%dotState(:,me) + plasticState(ph)%dotState(:,me) = A(1,stage) * plastic_RKdotState(1:sizeDotState,1) + + do n = 2, stage + plasticState(ph)%dotState(:,me) = plasticState(ph)%dotState(:,me) & + + A(n,stage) * plastic_RKdotState(1:sizeDotState,n) + enddo + + plasticState(ph)%state(1:sizeDotState,me) = plasticState(ph)%subState0(1:sizeDotState,me) & + + plasticState(ph)%dotState (1:sizeDotState,me) * Delta_t + + broken = integrateStress(F_0 + (F - F_0) * Delta_t * C(stage),Delta_t * C(stage),co,ip,el) + if(broken) exit + + broken = mech_collectDotState(Delta_t*C(stage),co,ip,el,ph,me) + if(broken) exit + + enddo + if(broken) return + + + plastic_RKdotState(1:sizeDotState,size(B)) = plasticState (ph)%dotState(:,me) + plasticState(ph)%dotState(:,me) = matmul(plastic_RKdotState(1:sizeDotState,1:size(B)),B) + plasticState(ph)%state(1:sizeDotState,me) = plasticState(ph)%subState0(1:sizeDotState,me) & + + plasticState(ph)%dotState (1:sizeDotState,me) * Delta_t + + if(present(DB)) & + broken = .not. converged(matmul(plastic_RKdotState(1:sizeDotState,1:size(DB)),DB) * Delta_t, & + plasticState(ph)%state(1:sizeDotState,me), & + plasticState(ph)%atol(1:sizeDotState)) + + if(broken) return + + broken = constitutive_deltaState(crystallite_S(1:3,1:3,co,ip,el), & + constitutive_mech_Fi(ph)%data(1:3,1:3,me),co,ip,el,ph,me) + if(broken) return + + broken = integrateStress(F,Delta_t,co,ip,el) + +end function integrateStateRK + + +!-------------------------------------------------------------------------------------------------- +!> @brief writes crystallite results to HDF5 output file +!-------------------------------------------------------------------------------------------------- +subroutine crystallite_results(group,ph) + + character(len=*), intent(in) :: group + integer, intent(in) :: ph + + integer :: ou + real(pReal), allocatable, dimension(:,:,:) :: selected_tensors + real(pReal), allocatable, dimension(:,:) :: selected_rotations + character(len=:), allocatable :: structureLabel + + + call results_closeGroup(results_addGroup(group//'/mechanics/')) + + do ou = 1, size(output_constituent(ph)%label) + + select case (output_constituent(ph)%label(ou)) + case('F') + selected_tensors = select_tensors(crystallite_F,ph) + call results_writeDataset(group//'/mechanics/',selected_tensors,output_constituent(ph)%label(ou),& + 'deformation gradient','1') + case('F_e') + selected_tensors = select_tensors(crystallite_Fe,ph) + call results_writeDataset(group//'/mechanics/',selected_tensors,output_constituent(ph)%label(ou),& + 'elastic deformation gradient','1') + case('F_p') + call results_writeDataset(group//'/mechanics/',constitutive_mech_Fp(ph)%data,output_constituent(ph)%label(ou),& + 'plastic deformation gradient','1') + case('F_i') + call results_writeDataset(group//'/mechanics/',constitutive_mech_Fi(ph)%data,output_constituent(ph)%label(ou),& + 'inelastic deformation gradient','1') + case('L_p') + selected_tensors = select_tensors(crystallite_Lp,ph) + call results_writeDataset(group//'/mechanics/',selected_tensors,output_constituent(ph)%label(ou),& + 'plastic velocity gradient','1/s') + case('L_i') + call results_writeDataset(group//'/mechanics/',constitutive_mech_Li(ph)%data,output_constituent(ph)%label(ou),& + 'inelastic velocity gradient','1/s') + case('P') + selected_tensors = select_tensors(crystallite_P,ph) + call results_writeDataset(group//'/mechanics/',selected_tensors,output_constituent(ph)%label(ou),& + 'First Piola-Kirchhoff stress','Pa') + case('S') + selected_tensors = select_tensors(crystallite_S,ph) + call results_writeDataset(group//'/mechanics/',selected_tensors,output_constituent(ph)%label(ou),& + 'Second Piola-Kirchhoff stress','Pa') + case('O') + select case(lattice_structure(ph)) + case(lattice_ISO_ID) + structureLabel = 'aP' + case(lattice_FCC_ID) + structureLabel = 'cF' + case(lattice_BCC_ID) + structureLabel = 'cI' + case(lattice_BCT_ID) + structureLabel = 'tI' + case(lattice_HEX_ID) + structureLabel = 'hP' + case(lattice_ORT_ID) + structureLabel = 'oP' + end select + selected_rotations = select_rotations(crystallite_orientation,ph) + call results_writeDataset(group//'/mechanics/',selected_rotations,output_constituent(ph)%label(ou),& + 'crystal orientation as quaternion','q_0 (q_1 q_2 q_3)') + call results_addAttribute('Lattice',structureLabel,group//'/mechanics/'//output_constituent(ph)%label(ou)) + end select + enddo + + + contains + + !------------------------------------------------------------------------------------------------ + !> @brief select tensors for output + !------------------------------------------------------------------------------------------------ + function select_tensors(dataset,ph) + + integer, intent(in) :: ph + real(pReal), dimension(:,:,:,:,:), intent(in) :: dataset + real(pReal), allocatable, dimension(:,:,:) :: select_tensors + integer :: el,ip,co,j + + allocate(select_tensors(3,3,count(material_phaseAt==ph)*discretization_nIPs)) + + j=0 + do el = 1, size(material_phaseAt,2) + do ip = 1, discretization_nIPs + do co = 1, size(material_phaseAt,1) !ToDo: this needs to be changed for varying Ngrains + if (material_phaseAt(co,el) == ph) then + j = j + 1 + select_tensors(1:3,1:3,j) = dataset(1:3,1:3,co,ip,el) + endif + enddo + enddo + enddo + + end function select_tensors + + +!-------------------------------------------------------------------------------------------------- +!> @brief select rotations for output +!-------------------------------------------------------------------------------------------------- + function select_rotations(dataset,ph) + + integer, intent(in) :: ph + type(rotation), dimension(:,:,:), intent(in) :: dataset + real(pReal), allocatable, dimension(:,:) :: select_rotations + integer :: el,ip,co,j + + allocate(select_rotations(4,count(material_phaseAt==ph)*homogenization_maxNconstituents*discretization_nIPs)) + + j=0 + do el = 1, size(material_phaseAt,2) + do ip = 1, discretization_nIPs + do co = 1, size(material_phaseAt,1) !ToDo: this needs to be changed for varying Ngrains + if (material_phaseAt(co,el) == ph) then + j = j + 1 + select_rotations(1:4,j) = dataset(co,ip,el)%asQuaternion() + endif + enddo + enddo + enddo + + end function select_rotations + +end subroutine crystallite_results + + +!-------------------------------------------------------------------------------------------------- +!> @brief Backup data for homog cutback. +!-------------------------------------------------------------------------------------------------- +module subroutine mech_initializeRestorationPoints(ph,me) + + integer, intent(in) :: ph, me + + + constitutive_mech_partitionedFi0(ph)%data(1:3,1:3,me) = constitutive_mech_Fi0(ph)%data(1:3,1:3,me) + constitutive_mech_partitionedFp0(ph)%data(1:3,1:3,me) = constitutive_mech_Fp0(ph)%data(1:3,1:3,me) + constitutive_mech_partitionedLi0(ph)%data(1:3,1:3,me) = constitutive_mech_Li0(ph)%data(1:3,1:3,me) + plasticState(ph)%partitionedState0(:,me) = plasticState(ph)%state0(:,me) + +end subroutine mech_initializeRestorationPoints + + +!-------------------------------------------------------------------------------------------------- +!> @brief Wind homog inc forward. +!-------------------------------------------------------------------------------------------------- +module subroutine constitutive_mech_windForward(ph,me) + + integer, intent(in) :: ph, me + + + constitutive_mech_partitionedFp0(ph)%data(1:3,1:3,me) = constitutive_mech_Fp(ph)%data(1:3,1:3,me) + constitutive_mech_partitionedFi0(ph)%data(1:3,1:3,me) = constitutive_mech_Fi(ph)%data(1:3,1:3,me) + constitutive_mech_partitionedLi0(ph)%data(1:3,1:3,me) = constitutive_mech_Li(ph)%data(1:3,1:3,me) + + plasticState(ph)%partitionedState0(:,me) = plasticState(ph)%state(:,me) + +end subroutine constitutive_mech_windForward + + +!-------------------------------------------------------------------------------------------------- +!> @brief Forward data after successful increment. +! ToDo: Any guessing for the current states possible? +!-------------------------------------------------------------------------------------------------- +module subroutine constitutive_mech_forward() + + integer :: ph + + + do ph = 1, size(plasticState) + plasticState(ph)%state0 = plasticState(ph)%state + constitutive_mech_Fi0(ph) = constitutive_mech_Fi(ph) + constitutive_mech_Fp0(ph) = constitutive_mech_Fp(ph) + constitutive_mech_Li0(ph) = constitutive_mech_Li(ph) + enddo + +end subroutine constitutive_mech_forward + + + +!-------------------------------------------------------------------------------------------------- +!> @brief returns the homogenize elasticity matrix +!> ToDo: homogenizedC66 would be more consistent +!-------------------------------------------------------------------------------------------------- +module function constitutive_homogenizedC(co,ip,el) result(C) + + real(pReal), dimension(6,6) :: C + integer, intent(in) :: & + co, & !< component-ID of integration point + ip, & !< integration point + el !< element + + plasticityType: select case (phase_plasticity(material_phaseAt(co,el))) + case (PLASTICITY_DISLOTWIN_ID) plasticityType + C = plastic_dislotwin_homogenizedC(co,ip,el) + case default plasticityType + C = lattice_C66(1:6,1:6,material_phaseAt(co,el)) + end select plasticityType + +end function constitutive_homogenizedC + + +!-------------------------------------------------------------------------------------------------- +!> @brief calculate stress (P) +!-------------------------------------------------------------------------------------------------- +module function crystallite_stress(dt,co,ip,el) result(converged_) + + real(pReal), intent(in) :: dt + integer, intent(in) :: & + co, & + ip, & + el + logical :: converged_ + + real(pReal) :: & + formerSubStep + integer :: & + NiterationCrystallite, & ! number of iterations in crystallite loop + so, ph, me + logical :: todo + real(pReal) :: subFrac,subStep + real(pReal), dimension(3,3) :: & + subLp0, & !< plastic velocity grad at start of crystallite inc + subLi0, & !< intermediate velocity grad at start of crystallite inc + subF0, & + subF + + + ph = material_phaseAt(co,el) + me = material_phaseMemberAt(co,ip,el) + subLi0 = constitutive_mech_partitionedLi0(ph)%data(1:3,1:3,me) + subLp0 = crystallite_partitionedLp0(1:3,1:3,co,ip,el) + + plasticState(ph)%subState0(:,me) = plasticState(ph)%partitionedState0(:,me) + do so = 1, phase_Nsources(ph) + sourceState(ph)%p(so)%subState0(:,me) = sourceState(ph)%p(so)%partitionedState0(:,me) + enddo + crystallite_subFp0(1:3,1:3,co,ip,el) = constitutive_mech_partitionedFp0(ph)%data(1:3,1:3,me) + crystallite_subFi0(1:3,1:3,co,ip,el) = constitutive_mech_partitionedFi0(ph)%data(1:3,1:3,me) + subF0 = crystallite_partitionedF0(1:3,1:3,co,ip,el) + subFrac = 0.0_pReal + subStep = 1.0_pReal/num%subStepSizeCryst + todo = .true. + converged_ = .false. ! pretend failed step of 1/subStepSizeCryst + + todo = .true. + NiterationCrystallite = 0 + cutbackLooping: do while (todo) + NiterationCrystallite = NiterationCrystallite + 1 + +!-------------------------------------------------------------------------------------------------- +! wind forward + if (converged_) then + formerSubStep = subStep + subFrac = subFrac + subStep + subStep = min(1.0_pReal - subFrac, num%stepIncreaseCryst * subStep) + + todo = subStep > 0.0_pReal ! still time left to integrate on? + + if (todo) then + subF0 = subF + subLp0 = crystallite_Lp (1:3,1:3,co,ip,el) + subLi0 = constitutive_mech_Li(ph)%data(1:3,1:3,me) + crystallite_subFp0(1:3,1:3,co,ip,el) = constitutive_mech_Fp(ph)%data(1:3,1:3,me) + crystallite_subFi0(1:3,1:3,co,ip,el) = constitutive_mech_Fi(ph)%data(1:3,1:3,me) + plasticState(ph)%subState0(:,me) = plasticState(ph)%state(:,me) + do so = 1, phase_Nsources(ph) + sourceState(ph)%p(so)%subState0(:,me) = sourceState(ph)%p(so)%state(:,me) + enddo + endif +!-------------------------------------------------------------------------------------------------- +! cut back (reduced time and restore) + else + subStep = num%subStepSizeCryst * subStep + constitutive_mech_Fp(ph)%data(1:3,1:3,me) = crystallite_subFp0(1:3,1:3,co,ip,el) + constitutive_mech_Fi(ph)%data(1:3,1:3,me) = crystallite_subFi0(1:3,1:3,co,ip,el) + crystallite_S (1:3,1:3,co,ip,el) = crystallite_S0 (1:3,1:3,co,ip,el) + if (subStep < 1.0_pReal) then ! actual (not initial) cutback + crystallite_Lp (1:3,1:3,co,ip,el) = subLp0 + constitutive_mech_Li(ph)%data(1:3,1:3,me) = subLi0 + endif + plasticState(ph)%state(:,me) = plasticState(ph)%subState0(:,me) + do so = 1, phase_Nsources(ph) + sourceState(ph)%p(so)%state(:,me) = sourceState(ph)%p(so)%subState0(:,me) + enddo + + todo = subStep > num%subStepMinCryst ! still on track or already done (beyond repair) + endif + +!-------------------------------------------------------------------------------------------------- +! prepare for integration + if (todo) then + subF = subF0 & + + subStep * (crystallite_F(1:3,1:3,co,ip,el) - crystallite_partitionedF0(1:3,1:3,co,ip,el)) + crystallite_Fe(1:3,1:3,co,ip,el) = matmul(subF,math_inv33(matmul(constitutive_mech_Fi(ph)%data(1:3,1:3,me), & + constitutive_mech_Fp(ph)%data(1:3,1:3,me)))) + crystallite_subdt(co,ip,el) = subStep * dt + converged_ = .not. integrateState(subF0,subF,subStep * dt,co,ip,el) + converged_ = converged_ .and. .not. integrateSourceState(subStep * dt,co,ip,el) + endif + + enddo cutbackLooping + +end function crystallite_stress + + +!-------------------------------------------------------------------------------------------------- +!> @brief Restore data after homog cutback. +!-------------------------------------------------------------------------------------------------- +module subroutine mech_restore(ip,el,includeL) + + integer, intent(in) :: & + ip, & !< integration point number + el !< element number + logical, intent(in) :: & + includeL !< protect agains fake cutback + integer :: & + co, p, m !< constituent number + + do co = 1,homogenization_Nconstituents(material_homogenizationAt(el)) + p = material_phaseAt(co,el) + m = material_phaseMemberAt(co,ip,el) + if (includeL) then + crystallite_Lp(1:3,1:3,co,ip,el) = crystallite_partitionedLp0(1:3,1:3,co,ip,el) + constitutive_mech_Li(p)%data(1:3,1:3,m) = constitutive_mech_partitionedLi0(p)%data(1:3,1:3,m) + endif ! maybe protecting everything from overwriting makes more sense + + constitutive_mech_Fp(p)%data(1:3,1:3,m) = constitutive_mech_partitionedFp0(p)%data(1:3,1:3,m) + constitutive_mech_Fi(p)%data(1:3,1:3,m) = constitutive_mech_partitionedFi0(p)%data(1:3,1:3,m) + crystallite_S (1:3,1:3,co,ip,el) = crystallite_partitionedS0 (1:3,1:3,co,ip,el) + + plasticState (material_phaseAt(co,el))%state( :,material_phasememberAt(co,ip,el)) = & + plasticState (material_phaseAt(co,el))%partitionedState0(:,material_phasememberAt(co,ip,el)) + enddo + +end subroutine mech_restore end submodule constitutive_mech diff --git a/src/constitutive_plastic_dislotwin.f90 b/src/constitutive_plastic_dislotwin.f90 index 4234a55b8..0474427fe 100644 --- a/src/constitutive_plastic_dislotwin.f90 +++ b/src/constitutive_plastic_dislotwin.f90 @@ -485,12 +485,12 @@ end function plastic_dislotwin_init !-------------------------------------------------------------------------------------------------- !> @brief Return the homogenized elasticity matrix. !-------------------------------------------------------------------------------------------------- -module function plastic_dislotwin_homogenizedC(ipc,ip,el) result(homogenizedC) +module function plastic_dislotwin_homogenizedC(co,ip,el) result(homogenizedC) real(pReal), dimension(6,6) :: & homogenizedC integer, intent(in) :: & - ipc, & !< component-ID of integration point + co, & !< component-ID of integration point ip, & !< integration point el !< element @@ -498,9 +498,9 @@ module function plastic_dislotwin_homogenizedC(ipc,ip,el) result(homogenizedC) of real(pReal) :: f_unrotated - of = material_phasememberAt(ipc,ip,el) - associate(prm => param(phase_plasticityInstance(material_phaseAt(ipc,el))),& - stt => state(phase_plasticityInstance(material_phaseAT(ipc,el)))) + of = material_phasememberAt(co,ip,el) + associate(prm => param(phase_plasticityInstance(material_phaseAt(co,el))),& + stt => state(phase_plasticityInstance(material_phaseAT(co,el)))) f_unrotated = 1.0_pReal & - sum(stt%f_tw(1:prm%sum_N_tw,of)) & diff --git a/src/constitutive_plastic_nonlocal.f90 b/src/constitutive_plastic_nonlocal.f90 index ce9e4e391..0d7875291 100644 --- a/src/constitutive_plastic_nonlocal.f90 +++ b/src/constitutive_plastic_nonlocal.f90 @@ -10,7 +10,8 @@ submodule(constitutive:constitutive_mech) plastic_nonlocal IPneighborhood => geometry_plastic_nonlocal_IPneighborhood, & IPvolume => geometry_plastic_nonlocal_IPvolume0, & IParea => geometry_plastic_nonlocal_IParea0, & - IPareaNormal => geometry_plastic_nonlocal_IPareaNormal0 + IPareaNormal => geometry_plastic_nonlocal_IPareaNormal0, & + geometry_plastic_nonlocal_disable real(pReal), parameter :: & kB = 1.38e-23_pReal !< Boltzmann constant in J/Kelvin @@ -195,7 +196,7 @@ module function plastic_nonlocal_init() result(myPlasticity) call geometry_plastic_nonlocal_disable return endif - + print*, 'Reuber et al., Acta Materialia 71:333–348, 2014' print*, 'https://doi.org/10.1016/j.actamat.2014.03.012'//IO_EOL @@ -551,11 +552,10 @@ end function plastic_nonlocal_init !-------------------------------------------------------------------------------------------------- !> @brief calculates quantities characterizing the microstructure !-------------------------------------------------------------------------------------------------- -module subroutine plastic_nonlocal_dependentState(F, Fp, instance, of, ip, el) +module subroutine plastic_nonlocal_dependentState(F, instance, of, ip, el) real(pReal), dimension(3,3), intent(in) :: & - F, & - Fp + F integer, intent(in) :: & instance, & of, & @@ -563,6 +563,8 @@ module subroutine plastic_nonlocal_dependentState(F, Fp, instance, of, ip, el) el integer :: & + ph, & + me, & no, & !< neighbor offset neighbor_el, & ! element number of neighboring material point neighbor_ip, & ! integration point of neighboring material point @@ -642,8 +644,10 @@ module subroutine plastic_nonlocal_dependentState(F, Fp, instance, of, ip, el) rho0 = getRho0(instance,of,ip,el) if (.not. phase_localPlasticity(material_phaseAt(1,el)) .and. prm%shortRangeStressCorrection) then - invFp = math_inv33(Fp) - invFe = matmul(Fp,math_inv33(F)) + ph = material_phaseAt(1,el) + me = material_phaseMemberAt(1,ip,el) + invFp = math_inv33(constitutive_mech_Fp(ph)%data(1:3,1:3,me)) + invFe = matmul(constitutive_mech_Fp(ph)%data(1:3,1:3,me),math_inv33(F)) rho_edg_delta = rho0(:,mob_edg_pos) - rho0(:,mob_edg_neg) rho_scr_delta = rho0(:,mob_scr_pos) - rho0(:,mob_scr_neg) @@ -972,14 +976,13 @@ end subroutine plastic_nonlocal_deltaState !--------------------------------------------------------------------------------------------------- !> @brief calculates the rate of change of microstructure !--------------------------------------------------------------------------------------------------- -module subroutine plastic_nonlocal_dotState(Mp, F, Fp, Temperature,timestep, & +module subroutine plastic_nonlocal_dotState(Mp, F, Temperature,timestep, & instance,of,ip,el) real(pReal), dimension(3,3), intent(in) :: & Mp !< MandelStress real(pReal), dimension(3,3,homogenization_maxNconstituents,discretization_nIPs,discretization_Nelems), intent(in) :: & - F, & !< elastic deformation gradient - Fp !< plastic deformation gradient + F !< Deformation gradient real(pReal), intent(in) :: & Temperature, & !< temperature timestep !< substepped crystallite time increment @@ -1146,7 +1149,7 @@ module subroutine plastic_nonlocal_dotState(Mp, F, Fp, Temperature,timestep, & - rhoDip(s,1) / timestep - rhoDotAthermalAnnihilation(s,9) & - rhoDotSingle2DipoleGlide(s,9)) ! make sure that we do not annihilate more dipoles than we have - rhoDot = rhoDotFlux(F,Fp,timestep, instance,of,ip,el) & + rhoDot = rhoDotFlux(F,timestep, instance,of,ip,el) & + rhoDotMultiplication & + rhoDotSingle2DipoleGlide & + rhoDotAthermalAnnihilation & @@ -1175,11 +1178,10 @@ end subroutine plastic_nonlocal_dotState !--------------------------------------------------------------------------------------------------- !> @brief calculates the rate of change of microstructure !--------------------------------------------------------------------------------------------------- -function rhoDotFlux(F,Fp,timestep, instance,of,ip,el) +function rhoDotFlux(F,timestep, instance,of,ip,el) real(pReal), dimension(3,3,homogenization_maxNconstituents,discretization_nIPs,discretization_Nelems), intent(in) :: & - F, & !< elastic deformation gradient - Fp !< plastic deformation gradient + F !< Deformation gradient real(pReal), intent(in) :: & timestep !< substepped crystallite time increment integer, intent(in) :: & @@ -1292,7 +1294,7 @@ function rhoDotFlux(F,Fp,timestep, instance,of,ip,el) m(1:3,:,4) = prm%slip_transverse my_F = F(1:3,1:3,1,ip,el) - my_Fe = matmul(my_F, math_inv33(Fp(1:3,1:3,1,ip,el))) + my_Fe = matmul(my_F, math_inv33(constitutive_mech_Fp(ph)%data(1:3,1:3,of))) neighbors: do n = 1,nIPneighbors @@ -1310,7 +1312,7 @@ function rhoDotFlux(F,Fp,timestep, instance,of,ip,el) if (neighbor_n > 0) then ! if neighbor exists, average deformation gradient neighbor_instance = phase_plasticityInstance(material_phaseAt(1,neighbor_el)) neighbor_F = F(1:3,1:3,1,neighbor_ip,neighbor_el) - neighbor_Fe = matmul(neighbor_F, math_inv33(Fp(1:3,1:3,1,neighbor_ip,neighbor_el))) + neighbor_Fe = matmul(neighbor_F, math_inv33(constitutive_mech_Fp(np)%data(1:3,1:3,no))) Favg = 0.5_pReal * (my_F + neighbor_F) else ! if no neighbor, take my value as average Favg = my_F diff --git a/src/crystallite.f90 b/src/crystallite.f90 deleted file mode 100644 index da349bbcd..000000000 --- a/src/crystallite.f90 +++ /dev/null @@ -1,1646 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -!> @author Martin Diehl, Max-Planck-Institut für Eisenforschung GmbH -!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH -!> @author Franz Roters, Max-Planck-Institut für Eisenforschung GmbH -!> @author Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH -!> @author Christoph Kords, Max-Planck-Institut für Eisenforschung GmbH -!> @author Chen Zhang, Michigan State University -!> @brief crystallite state integration functions and reporting of results -!-------------------------------------------------------------------------------------------------- - -module crystallite - use prec - use parallelization - use IO - use HDF5_utilities - use DAMASK_interface - use config - use rotations - use math - use FEsolving - use material - use constitutive - use discretization - use lattice - use results - - implicit none - private - - real(pReal), dimension(:,:,:), allocatable, public :: & - crystallite_dt !< requested time increment of each grain - real(pReal), dimension(:,:,:), allocatable :: & - crystallite_subdt, & !< substepped time increment of each grain - crystallite_subFrac, & !< already calculated fraction of increment - crystallite_subStep !< size of next integration step - type(rotation), dimension(:,:,:), allocatable :: & - crystallite_orientation !< current orientation - real(pReal), dimension(:,:,:,:,:), allocatable :: & - crystallite_F0, & !< def grad at start of FE inc - crystallite_subF, & !< def grad to be reached at end of crystallite inc - crystallite_subF0, & !< def grad at start of crystallite inc - ! - crystallite_Fe, & !< current "elastic" def grad (end of converged time step) - ! - crystallite_Fp, & !< current plastic def grad (end of converged time step) - crystallite_Fp0, & !< plastic def grad at start of FE inc - crystallite_partitionedFp0,& !< plastic def grad at start of homog inc - crystallite_subFp0,& !< plastic def grad at start of crystallite inc - ! - crystallite_Fi, & !< current intermediate def grad (end of converged time step) - crystallite_Fi0, & !< intermediate def grad at start of FE inc - crystallite_partitionedFi0,& !< intermediate def grad at start of homog inc - crystallite_subFi0,& !< intermediate def grad at start of crystallite inc - ! - crystallite_Lp0, & !< plastic velocitiy grad at start of FE inc - crystallite_partitionedLp0, & !< plastic velocity grad at start of homog inc - ! - crystallite_Li, & !< current intermediate velocitiy grad (end of converged time step) - crystallite_Li0, & !< intermediate velocitiy grad at start of FE inc - crystallite_partitionedLi0, & !< intermediate velocity grad at start of homog inc - ! - crystallite_S0, & !< 2nd Piola-Kirchhoff stress vector at start of FE inc - crystallite_partitionedS0 !< 2nd Piola-Kirchhoff stress vector at start of homog inc - real(pReal), dimension(:,:,:,:,:), allocatable, public, protected :: & - crystallite_P, & !< 1st Piola-Kirchhoff stress per grain - crystallite_Lp, & !< current plastic velocitiy grad (end of converged time step) - crystallite_S, & !< current 2nd Piola-Kirchhoff stress vector (end of converged time step) - crystallite_partitionedF0 !< def grad at start of homog inc - real(pReal), dimension(:,:,:,:,:), allocatable, public :: & - crystallite_partitionedF !< def grad to be reached at end of homog inc - - logical, dimension(:,:,:), allocatable, public :: & - crystallite_requested !< used by upper level (homogenization) to request crystallite calculation - logical, dimension(:,:,:), allocatable :: & - crystallite_converged !< convergence flag - - type :: tOutput !< new requested output (per phase) - character(len=pStringLen), allocatable, dimension(:) :: & - label - end type tOutput - type(tOutput), allocatable, dimension(:) :: output_constituent - - type :: tNumerics - integer :: & - iJacoLpresiduum, & !< frequency of Jacobian update of residuum in Lp - nState, & !< state loop limit - nStress !< stress loop limit - real(pReal) :: & - subStepMinCryst, & !< minimum (relative) size of sub-step allowed during cutback - subStepSizeCryst, & !< size of first substep when cutback - subStepSizeLp, & !< size of first substep when cutback in Lp calculation - subStepSizeLi, & !< size of first substep when cutback in Li calculation - stepIncreaseCryst, & !< increase of next substep size when previous substep converged - rtol_crystalliteState, & !< relative tolerance in state loop - rtol_crystalliteStress, & !< relative tolerance in stress loop - atol_crystalliteStress !< absolute tolerance in stress loop - end type tNumerics - - type(tNumerics) :: num ! numerics parameters. Better name? - - type :: tDebugOptions - logical :: & - basic, & - extensive, & - selective - integer :: & - element, & - ip, & - grain - end type tDebugOptions - - type(tDebugOptions) :: debugCrystallite - - procedure(integrateStateFPI), pointer :: integrateState - - public :: & - crystallite_init, & - crystallite_stress, & - crystallite_stressTangent, & - crystallite_orientations, & - crystallite_push33ToRef, & - crystallite_results, & - crystallite_restartWrite, & - crystallite_restartRead, & - crystallite_forward, & - crystallite_initializeRestorationPoints, & - crystallite_windForward, & - crystallite_restore - -contains - - -!-------------------------------------------------------------------------------------------------- -!> @brief allocates and initialize per grain variables -!-------------------------------------------------------------------------------------------------- -subroutine crystallite_init - - logical, dimension(discretization_nIPs,discretization_Nelems) :: devNull - integer :: & - c, & !< counter in integration point component loop - i, & !< counter in integration point loop - e, & !< counter in element loop - cMax, & !< maximum number of integration point components - iMax, & !< maximum number of integration points - eMax !< maximum number of elements - - - class(tNode), pointer :: & - num_crystallite, & - debug_crystallite, & ! pointer to debug options for crystallite - phases, & - phase, & - mech - - print'(/,a)', ' <<<+- crystallite init -+>>>' - - debug_crystallite => config_debug%get('crystallite', defaultVal=emptyList) - debugCrystallite%basic = debug_crystallite%contains('basic') - debugCrystallite%extensive = debug_crystallite%contains('extensive') - debugCrystallite%selective = debug_crystallite%contains('selective') - debugCrystallite%element = config_debug%get_asInt('element', defaultVal=1) - debugCrystallite%ip = config_debug%get_asInt('integrationpoint', defaultVal=1) - debugCrystallite%grain = config_debug%get_asInt('grain', defaultVal=1) - - cMax = homogenization_maxNconstituents - iMax = discretization_nIPs - eMax = discretization_Nelems - - allocate(crystallite_partitionedF(3,3,cMax,iMax,eMax),source=0.0_pReal) - - allocate(crystallite_S0, & - crystallite_F0, crystallite_Fi0,crystallite_Fp0, & - crystallite_Li0,crystallite_Lp0, & - crystallite_partitionedS0, & - crystallite_partitionedF0,crystallite_partitionedFp0,crystallite_partitionedFi0, & - crystallite_partitionedLp0,crystallite_partitionedLi0, & - crystallite_S,crystallite_P, & - crystallite_Fe,crystallite_Fi,crystallite_Fp, & - crystallite_Li,crystallite_Lp, & - crystallite_subF,crystallite_subF0, & - crystallite_subFp0,crystallite_subFi0, & - source = crystallite_partitionedF) - - allocate(crystallite_dt(cMax,iMax,eMax),source=0.0_pReal) - allocate(crystallite_subdt,crystallite_subFrac,crystallite_subStep, & - source = crystallite_dt) - - allocate(crystallite_orientation(cMax,iMax,eMax)) - - allocate(crystallite_requested(cMax,iMax,eMax), source=.false.) - allocate(crystallite_converged(cMax,iMax,eMax), source=.true.) - - num_crystallite => config_numerics%get('crystallite',defaultVal=emptyDict) - - num%subStepMinCryst = num_crystallite%get_asFloat ('subStepMin', defaultVal=1.0e-3_pReal) - num%subStepSizeCryst = num_crystallite%get_asFloat ('subStepSize', defaultVal=0.25_pReal) - num%stepIncreaseCryst = num_crystallite%get_asFloat ('stepIncrease', defaultVal=1.5_pReal) - num%subStepSizeLp = num_crystallite%get_asFloat ('subStepSizeLp', defaultVal=0.5_pReal) - num%subStepSizeLi = num_crystallite%get_asFloat ('subStepSizeLi', defaultVal=0.5_pReal) - num%rtol_crystalliteState = num_crystallite%get_asFloat ('rtol_State', defaultVal=1.0e-6_pReal) - num%rtol_crystalliteStress = num_crystallite%get_asFloat ('rtol_Stress', defaultVal=1.0e-6_pReal) - num%atol_crystalliteStress = num_crystallite%get_asFloat ('atol_Stress', defaultVal=1.0e-8_pReal) - num%iJacoLpresiduum = num_crystallite%get_asInt ('iJacoLpresiduum', defaultVal=1) - num%nState = num_crystallite%get_asInt ('nState', defaultVal=20) - num%nStress = num_crystallite%get_asInt ('nStress', defaultVal=40) - - if(num%subStepMinCryst <= 0.0_pReal) call IO_error(301,ext_msg='subStepMinCryst') - if(num%subStepSizeCryst <= 0.0_pReal) call IO_error(301,ext_msg='subStepSizeCryst') - if(num%stepIncreaseCryst <= 0.0_pReal) call IO_error(301,ext_msg='stepIncreaseCryst') - - if(num%subStepSizeLp <= 0.0_pReal) call IO_error(301,ext_msg='subStepSizeLp') - if(num%subStepSizeLi <= 0.0_pReal) call IO_error(301,ext_msg='subStepSizeLi') - - if(num%rtol_crystalliteState <= 0.0_pReal) call IO_error(301,ext_msg='rtol_crystalliteState') - if(num%rtol_crystalliteStress <= 0.0_pReal) call IO_error(301,ext_msg='rtol_crystalliteStress') - if(num%atol_crystalliteStress <= 0.0_pReal) call IO_error(301,ext_msg='atol_crystalliteStress') - - if(num%iJacoLpresiduum < 1) call IO_error(301,ext_msg='iJacoLpresiduum') - - if(num%nState < 1) call IO_error(301,ext_msg='nState') - if(num%nStress< 1) call IO_error(301,ext_msg='nStress') - - select case(num_crystallite%get_asString('integrator',defaultVal='FPI')) - case('FPI') - integrateState => integrateStateFPI - case('Euler') - integrateState => integrateStateEuler - case('AdaptiveEuler') - integrateState => integrateStateAdaptiveEuler - case('RK4') - integrateState => integrateStateRK4 - case('RKCK45') - integrateState => integrateStateRKCK45 - case default - call IO_error(301,ext_msg='integrator') - end select - - phases => config_material%get('phase') - - allocate(output_constituent(phases%length)) - do c = 1, phases%length - phase => phases%get(c) - mech => phase%get('mechanics',defaultVal = emptyDict) -#if defined(__GFORTRAN__) - output_constituent(c)%label = output_asStrings(mech) -#else - output_constituent(c)%label = mech%get_asStrings('output',defaultVal=emptyStringArray) -#endif - enddo - - -!-------------------------------------------------------------------------------------------------- -! initialize - !$OMP PARALLEL DO PRIVATE(i,c) - do e = FEsolving_execElem(1),FEsolving_execElem(2) - do i = FEsolving_execIP(1), FEsolving_execIP(2); do c = 1, homogenization_Nconstituents(material_homogenizationAt(e)) - crystallite_Fp0(1:3,1:3,c,i,e) = material_orientation0(c,i,e)%asMatrix() ! Fp reflects initial orientation (see 10.1016/j.actamat.2006.01.005) - crystallite_Fp0(1:3,1:3,c,i,e) = crystallite_Fp0(1:3,1:3,c,i,e) & - / math_det33(crystallite_Fp0(1:3,1:3,c,i,e))**(1.0_pReal/3.0_pReal) - crystallite_Fi0(1:3,1:3,c,i,e) = constitutive_initialFi(c,i,e) - crystallite_F0(1:3,1:3,c,i,e) = math_I3 - crystallite_Fe(1:3,1:3,c,i,e) = math_inv33(matmul(crystallite_Fi0(1:3,1:3,c,i,e), & - crystallite_Fp0(1:3,1:3,c,i,e))) ! assuming that euler angles are given in internal strain free configuration - crystallite_Fp(1:3,1:3,c,i,e) = crystallite_Fp0(1:3,1:3,c,i,e) - crystallite_Fi(1:3,1:3,c,i,e) = crystallite_Fi0(1:3,1:3,c,i,e) - crystallite_requested(c,i,e) = .true. - enddo; enddo - enddo - !$OMP END PARALLEL DO - - - crystallite_partitionedFp0 = crystallite_Fp0 - crystallite_partitionedFi0 = crystallite_Fi0 - crystallite_partitionedF0 = crystallite_F0 - crystallite_partitionedF = crystallite_F0 - - call crystallite_orientations() - - !$OMP PARALLEL DO - do e = FEsolving_execElem(1),FEsolving_execElem(2) - do i = FEsolving_execIP(1),FEsolving_execIP(2) - do c = 1,homogenization_Nconstituents(material_homogenizationAt(e)) - call constitutive_dependentState(crystallite_partitionedF0(1:3,1:3,c,i,e), & - crystallite_partitionedFp0(1:3,1:3,c,i,e), & - c,i,e) ! update dependent state variables to be consistent with basic states - enddo - enddo - enddo - !$OMP END PARALLEL DO - - devNull = crystallite_stress() - -#ifdef DEBUG - if (debugCrystallite%basic) then - print'(a42,1x,i10)', ' # of elements: ', eMax - print'(a42,1x,i10)', ' # of integration points/element: ', iMax - print'(a42,1x,i10)', 'max # of constituents/integration point: ', cMax - flush(IO_STDOUT) - endif -#endif - -end subroutine crystallite_init - - -!-------------------------------------------------------------------------------------------------- -!> @brief calculate stress (P) -!-------------------------------------------------------------------------------------------------- -function crystallite_stress() - - logical, dimension(discretization_nIPs,discretization_Nelems) :: crystallite_stress - real(pReal) :: & - formerSubStep - integer :: & - NiterationCrystallite, & ! number of iterations in crystallite loop - c, & !< counter in integration point component loop - i, & !< counter in integration point loop - e, & !< counter in element loop - s - logical, dimension(homogenization_maxNconstituents,discretization_nIPs,discretization_Nelems) :: todo !ToDo: need to set some values to false for different Ngrains - real(pReal), dimension(:,:,:,:,:), allocatable :: & - subLp0,& !< plastic velocity grad at start of crystallite inc - subLi0 !< intermediate velocity grad at start of crystallite inc - - - todo = .false. - - subLp0 = crystallite_partitionedLp0 - subLi0 = crystallite_partitionedLi0 - - - -!-------------------------------------------------------------------------------------------------- -! initialize to starting condition - crystallite_subStep = 0.0_pReal - !$OMP PARALLEL DO - elementLooping1: do e = FEsolving_execElem(1),FEsolving_execElem(2) - do i = FEsolving_execIP(1),FEsolving_execIP(2); do c = 1,homogenization_Nconstituents(material_homogenizationAt(e)) - homogenizationRequestsCalculation: if (crystallite_requested(c,i,e)) then - plasticState (material_phaseAt(c,e))%subState0( :,material_phaseMemberAt(c,i,e)) = & - plasticState (material_phaseAt(c,e))%partitionedState0(:,material_phaseMemberAt(c,i,e)) - - do s = 1, phase_Nsources(material_phaseAt(c,e)) - sourceState(material_phaseAt(c,e))%p(s)%subState0( :,material_phaseMemberAt(c,i,e)) = & - sourceState(material_phaseAt(c,e))%p(s)%partitionedState0(:,material_phaseMemberAt(c,i,e)) - enddo - crystallite_subFp0(1:3,1:3,c,i,e) = crystallite_partitionedFp0(1:3,1:3,c,i,e) - crystallite_subFi0(1:3,1:3,c,i,e) = crystallite_partitionedFi0(1:3,1:3,c,i,e) - crystallite_subF0(1:3,1:3,c,i,e) = crystallite_partitionedF0(1:3,1:3,c,i,e) - crystallite_subFrac(c,i,e) = 0.0_pReal - crystallite_subStep(c,i,e) = 1.0_pReal/num%subStepSizeCryst - todo(c,i,e) = .true. - crystallite_converged(c,i,e) = .false. ! pretend failed step of 1/subStepSizeCryst - endif homogenizationRequestsCalculation - enddo; enddo - enddo elementLooping1 - !$OMP END PARALLEL DO - - NiterationCrystallite = 0 - cutbackLooping: do while (any(todo(:,FEsolving_execIP(1):FEsolving_execIP(2),FEsolving_execELem(1):FEsolving_execElem(2)))) - NiterationCrystallite = NiterationCrystallite + 1 - -#ifdef DEBUG - if (debugCrystallite%extensive) & - print'(a,i6)', '<< CRYST stress >> crystallite iteration ',NiterationCrystallite -#endif - !$OMP PARALLEL DO PRIVATE(formerSubStep) - elementLooping3: do e = FEsolving_execElem(1),FEsolving_execElem(2) - do i = FEsolving_execIP(1),FEsolving_execIP(2) - do c = 1,homogenization_Nconstituents(material_homogenizationAt(e)) -!-------------------------------------------------------------------------------------------------- -! wind forward - if (crystallite_converged(c,i,e)) then - formerSubStep = crystallite_subStep(c,i,e) - crystallite_subFrac(c,i,e) = crystallite_subFrac(c,i,e) + crystallite_subStep(c,i,e) - crystallite_subStep(c,i,e) = min(1.0_pReal - crystallite_subFrac(c,i,e), & - num%stepIncreaseCryst * crystallite_subStep(c,i,e)) - - todo(c,i,e) = crystallite_subStep(c,i,e) > 0.0_pReal ! still time left to integrate on? - if (todo(c,i,e)) then - crystallite_subF0 (1:3,1:3,c,i,e) = crystallite_subF(1:3,1:3,c,i,e) - subLp0(1:3,1:3,c,i,e) = crystallite_Lp (1:3,1:3,c,i,e) - subLi0(1:3,1:3,c,i,e) = crystallite_Li (1:3,1:3,c,i,e) - crystallite_subFp0(1:3,1:3,c,i,e) = crystallite_Fp (1:3,1:3,c,i,e) - crystallite_subFi0(1:3,1:3,c,i,e) = crystallite_Fi (1:3,1:3,c,i,e) - plasticState( material_phaseAt(c,e))%subState0(:,material_phaseMemberAt(c,i,e)) & - = plasticState(material_phaseAt(c,e))%state( :,material_phaseMemberAt(c,i,e)) - do s = 1, phase_Nsources(material_phaseAt(c,e)) - sourceState( material_phaseAt(c,e))%p(s)%subState0(:,material_phaseMemberAt(c,i,e)) & - = sourceState(material_phaseAt(c,e))%p(s)%state( :,material_phaseMemberAt(c,i,e)) - enddo - endif - -!-------------------------------------------------------------------------------------------------- -! cut back (reduced time and restore) - else - crystallite_subStep(c,i,e) = num%subStepSizeCryst * crystallite_subStep(c,i,e) - crystallite_Fp (1:3,1:3,c,i,e) = crystallite_subFp0(1:3,1:3,c,i,e) - crystallite_Fi (1:3,1:3,c,i,e) = crystallite_subFi0(1:3,1:3,c,i,e) - crystallite_S (1:3,1:3,c,i,e) = crystallite_S0 (1:3,1:3,c,i,e) - if (crystallite_subStep(c,i,e) < 1.0_pReal) then ! actual (not initial) cutback - crystallite_Lp (1:3,1:3,c,i,e) = subLp0(1:3,1:3,c,i,e) - crystallite_Li (1:3,1:3,c,i,e) = subLi0(1:3,1:3,c,i,e) - endif - plasticState (material_phaseAt(c,e))%state( :,material_phaseMemberAt(c,i,e)) & - = plasticState(material_phaseAt(c,e))%subState0(:,material_phaseMemberAt(c,i,e)) - do s = 1, phase_Nsources(material_phaseAt(c,e)) - sourceState( material_phaseAt(c,e))%p(s)%state( :,material_phaseMemberAt(c,i,e)) & - = sourceState(material_phaseAt(c,e))%p(s)%subState0(:,material_phaseMemberAt(c,i,e)) - enddo - - ! cant restore dotState here, since not yet calculated in first cutback after initialization - todo(c,i,e) = crystallite_subStep(c,i,e) > num%subStepMinCryst ! still on track or already done (beyond repair) - endif - -!-------------------------------------------------------------------------------------------------- -! prepare for integration - if (todo(c,i,e)) then - crystallite_subF(1:3,1:3,c,i,e) = crystallite_subF0(1:3,1:3,c,i,e) & - + crystallite_subStep(c,i,e) *( crystallite_partitionedF (1:3,1:3,c,i,e) & - -crystallite_partitionedF0(1:3,1:3,c,i,e)) - crystallite_Fe(1:3,1:3,c,i,e) = matmul(crystallite_subF(1:3,1:3,c,i,e), & - math_inv33(matmul(crystallite_Fi(1:3,1:3,c,i,e), & - crystallite_Fp(1:3,1:3,c,i,e)))) - crystallite_subdt(c,i,e) = crystallite_subStep(c,i,e) * crystallite_dt(c,i,e) - crystallite_converged(c,i,e) = .false. - call integrateState(c,i,e) - endif - - enddo - enddo - enddo elementLooping3 - !$OMP END PARALLEL DO - -!-------------------------------------------------------------------------------------------------- -! integrate --- requires fully defined state array (basic + dependent state) - where(.not. crystallite_converged .and. crystallite_subStep > num%subStepMinCryst) & ! do not try non-converged but fully cutbacked any further - todo = .true. ! TODO: again unroll this into proper elementloop to avoid N^2 for single point evaluation - - - enddo cutbackLooping - -! return whether converged or not - crystallite_stress = .false. - elementLooping5: do e = FEsolving_execElem(1),FEsolving_execElem(2) - do i = FEsolving_execIP(1),FEsolving_execIP(2) - crystallite_stress(i,e) = all(crystallite_converged(:,i,e)) - enddo - enddo elementLooping5 - -end function crystallite_stress - - -!-------------------------------------------------------------------------------------------------- -!> @brief Backup data for homog cutback. -!-------------------------------------------------------------------------------------------------- -subroutine crystallite_initializeRestorationPoints(i,e) - - integer, intent(in) :: & - i, & !< integration point number - e !< element number - integer :: & - c, & !< constituent number - s - - do c = 1,homogenization_Nconstituents(material_homogenizationAt(e)) - crystallite_partitionedFp0(1:3,1:3,c,i,e) = crystallite_Fp0(1:3,1:3,c,i,e) - crystallite_partitionedLp0(1:3,1:3,c,i,e) = crystallite_Lp0(1:3,1:3,c,i,e) - crystallite_partitionedFi0(1:3,1:3,c,i,e) = crystallite_Fi0(1:3,1:3,c,i,e) - crystallite_partitionedLi0(1:3,1:3,c,i,e) = crystallite_Li0(1:3,1:3,c,i,e) - crystallite_partitionedF0(1:3,1:3,c,i,e) = crystallite_F0(1:3,1:3,c,i,e) - crystallite_partitionedS0(1:3,1:3,c,i,e) = crystallite_S0(1:3,1:3,c,i,e) - - plasticState(material_phaseAt(c,e))%partitionedState0(:,material_phasememberAt(c,i,e)) = & - plasticState(material_phaseAt(c,e))%state0( :,material_phasememberAt(c,i,e)) - do s = 1, phase_Nsources(material_phaseAt(c,e)) - sourceState(material_phaseAt(c,e))%p(s)%partitionedState0(:,material_phasememberAt(c,i,e)) = & - sourceState(material_phaseAt(c,e))%p(s)%state0( :,material_phasememberAt(c,i,e)) - enddo - enddo - -end subroutine crystallite_initializeRestorationPoints - - -!-------------------------------------------------------------------------------------------------- -!> @brief Wind homog inc forward. -!-------------------------------------------------------------------------------------------------- -subroutine crystallite_windForward(i,e) - - integer, intent(in) :: & - i, & !< integration point number - e !< element number - integer :: & - c, & !< constituent number - s - - do c = 1,homogenization_Nconstituents(material_homogenizationAt(e)) - crystallite_partitionedF0 (1:3,1:3,c,i,e) = crystallite_partitionedF(1:3,1:3,c,i,e) - crystallite_partitionedFp0(1:3,1:3,c,i,e) = crystallite_Fp (1:3,1:3,c,i,e) - crystallite_partitionedLp0(1:3,1:3,c,i,e) = crystallite_Lp (1:3,1:3,c,i,e) - crystallite_partitionedFi0(1:3,1:3,c,i,e) = crystallite_Fi (1:3,1:3,c,i,e) - crystallite_partitionedLi0(1:3,1:3,c,i,e) = crystallite_Li (1:3,1:3,c,i,e) - crystallite_partitionedS0 (1:3,1:3,c,i,e) = crystallite_S (1:3,1:3,c,i,e) - - plasticState (material_phaseAt(c,e))%partitionedState0(:,material_phasememberAt(c,i,e)) = & - plasticState (material_phaseAt(c,e))%state (:,material_phasememberAt(c,i,e)) - do s = 1, phase_Nsources(material_phaseAt(c,e)) - sourceState(material_phaseAt(c,e))%p(s)%partitionedState0(:,material_phasememberAt(c,i,e)) = & - sourceState(material_phaseAt(c,e))%p(s)%state (:,material_phasememberAt(c,i,e)) - enddo - enddo - -end subroutine crystallite_windForward - - -!-------------------------------------------------------------------------------------------------- -!> @brief Restore data after homog cutback. -!-------------------------------------------------------------------------------------------------- -subroutine crystallite_restore(i,e,includeL) - - integer, intent(in) :: & - i, & !< integration point number - e !< element number - logical, intent(in) :: & - includeL !< protect agains fake cutback - integer :: & - c, & !< constituent number - s - - do c = 1,homogenization_Nconstituents(material_homogenizationAt(e)) - if (includeL) then - crystallite_Lp(1:3,1:3,c,i,e) = crystallite_partitionedLp0(1:3,1:3,c,i,e) - crystallite_Li(1:3,1:3,c,i,e) = crystallite_partitionedLi0(1:3,1:3,c,i,e) - endif ! maybe protecting everything from overwriting makes more sense - crystallite_Fp(1:3,1:3,c,i,e) = crystallite_partitionedFp0(1:3,1:3,c,i,e) - crystallite_Fi(1:3,1:3,c,i,e) = crystallite_partitionedFi0(1:3,1:3,c,i,e) - crystallite_S (1:3,1:3,c,i,e) = crystallite_partitionedS0 (1:3,1:3,c,i,e) - - plasticState (material_phaseAt(c,e))%state( :,material_phasememberAt(c,i,e)) = & - plasticState (material_phaseAt(c,e))%partitionedState0(:,material_phasememberAt(c,i,e)) - do s = 1, phase_Nsources(material_phaseAt(c,e)) - sourceState(material_phaseAt(c,e))%p(s)%state( :,material_phasememberAt(c,i,e)) = & - sourceState(material_phaseAt(c,e))%p(s)%partitionedState0(:,material_phasememberAt(c,i,e)) - enddo - enddo - -end subroutine crystallite_restore - - -!-------------------------------------------------------------------------------------------------- -!> @brief Calculate tangent (dPdF). -!-------------------------------------------------------------------------------------------------- -function crystallite_stressTangent(c,i,e) result(dPdF) - - real(pReal), dimension(3,3,3,3) :: dPdF - integer, intent(in) :: & - c, & !< counter in constituent loop - i, & !< counter in integration point loop - e !< counter in element loop - integer :: & - o, & - p - - real(pReal), dimension(3,3) :: devNull, & - invSubFp0,invSubFi0,invFp,invFi, & - temp_33_1, temp_33_2, temp_33_3, temp_33_4 - real(pReal), dimension(3,3,3,3) :: dSdFe, & - dSdF, & - dSdFi, & - dLidS, & ! tangent in lattice configuration - dLidFi, & - dLpdS, & - dLpdFi, & - dFidS, & - dFpinvdF, & - rhs_3333, & - lhs_3333, & - temp_3333 - real(pReal), dimension(9,9):: temp_99 - logical :: error - - - call constitutive_SandItsTangents(devNull,dSdFe,dSdFi, & - crystallite_Fe(1:3,1:3,c,i,e), & - crystallite_Fi(1:3,1:3,c,i,e),c,i,e) - call constitutive_LiAndItsTangents(devNull,dLidS,dLidFi, & - crystallite_S (1:3,1:3,c,i,e), & - crystallite_Fi(1:3,1:3,c,i,e), & - c,i,e) - - invFp = math_inv33(crystallite_Fp(1:3,1:3,c,i,e)) - invFi = math_inv33(crystallite_Fi(1:3,1:3,c,i,e)) - invSubFp0 = math_inv33(crystallite_subFp0(1:3,1:3,c,i,e)) - invSubFi0 = math_inv33(crystallite_subFi0(1:3,1:3,c,i,e)) - - if (sum(abs(dLidS)) < tol_math_check) then - dFidS = 0.0_pReal - else - lhs_3333 = 0.0_pReal; rhs_3333 = 0.0_pReal - do o=1,3; do p=1,3 - lhs_3333(1:3,1:3,o,p) = lhs_3333(1:3,1:3,o,p) & - + crystallite_subdt(c,i,e)*matmul(invSubFi0,dLidFi(1:3,1:3,o,p)) - lhs_3333(1:3,o,1:3,p) = lhs_3333(1:3,o,1:3,p) & - + invFi*invFi(p,o) - rhs_3333(1:3,1:3,o,p) = rhs_3333(1:3,1:3,o,p) & - - crystallite_subdt(c,i,e)*matmul(invSubFi0,dLidS(1:3,1:3,o,p)) - enddo; enddo - call math_invert(temp_99,error,math_3333to99(lhs_3333)) - if (error) then - call IO_warning(warning_ID=600,el=e,ip=i,g=c, & - ext_msg='inversion error in analytic tangent calculation') - dFidS = 0.0_pReal - else - dFidS = math_mul3333xx3333(math_99to3333(temp_99),rhs_3333) - endif - dLidS = math_mul3333xx3333(dLidFi,dFidS) + dLidS - endif - - call constitutive_LpAndItsTangents(devNull,dLpdS,dLpdFi, & - crystallite_S (1:3,1:3,c,i,e), & - crystallite_Fi(1:3,1:3,c,i,e),c,i,e) ! call constitutive law to calculate Lp tangent in lattice configuration - dLpdS = math_mul3333xx3333(dLpdFi,dFidS) + dLpdS - -!-------------------------------------------------------------------------------------------------- -! calculate dSdF - temp_33_1 = transpose(matmul(invFp,invFi)) - temp_33_2 = matmul(crystallite_subF(1:3,1:3,c,i,e),invSubFp0) - temp_33_3 = matmul(matmul(crystallite_subF(1:3,1:3,c,i,e),invFp), invSubFi0) - - do o=1,3; do p=1,3 - rhs_3333(p,o,1:3,1:3) = matmul(dSdFe(p,o,1:3,1:3),temp_33_1) - temp_3333(1:3,1:3,p,o) = matmul(matmul(temp_33_2,dLpdS(1:3,1:3,p,o)), invFi) & - + matmul(temp_33_3,dLidS(1:3,1:3,p,o)) - enddo; enddo - lhs_3333 = crystallite_subdt(c,i,e)*math_mul3333xx3333(dSdFe,temp_3333) & - + math_mul3333xx3333(dSdFi,dFidS) - - call math_invert(temp_99,error,math_eye(9)+math_3333to99(lhs_3333)) - if (error) then - call IO_warning(warning_ID=600,el=e,ip=i,g=c, & - ext_msg='inversion error in analytic tangent calculation') - dSdF = rhs_3333 - else - dSdF = math_mul3333xx3333(math_99to3333(temp_99),rhs_3333) - endif - -!-------------------------------------------------------------------------------------------------- -! calculate dFpinvdF - temp_3333 = math_mul3333xx3333(dLpdS,dSdF) - do o=1,3; do p=1,3 - dFpinvdF(1:3,1:3,p,o) = -crystallite_subdt(c,i,e) & - * matmul(invSubFp0, matmul(temp_3333(1:3,1:3,p,o),invFi)) - enddo; enddo - -!-------------------------------------------------------------------------------------------------- -! assemble dPdF - temp_33_1 = matmul(crystallite_S(1:3,1:3,c,i,e),transpose(invFp)) - temp_33_2 = matmul(invFp,temp_33_1) - temp_33_3 = matmul(crystallite_subF(1:3,1:3,c,i,e),invFp) - temp_33_4 = matmul(temp_33_3,crystallite_S(1:3,1:3,c,i,e)) - - dPdF = 0.0_pReal - do p=1,3 - dPdF(p,1:3,p,1:3) = transpose(temp_33_2) - enddo - do o=1,3; do p=1,3 - dPdF(1:3,1:3,p,o) = dPdF(1:3,1:3,p,o) & - + matmul(matmul(crystallite_subF(1:3,1:3,c,i,e), & - dFpinvdF(1:3,1:3,p,o)),temp_33_1) & - + matmul(matmul(temp_33_3,dSdF(1:3,1:3,p,o)), & - transpose(invFp)) & - + matmul(temp_33_4,transpose(dFpinvdF(1:3,1:3,p,o))) - enddo; enddo - -end function crystallite_stressTangent - - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates orientations -!-------------------------------------------------------------------------------------------------- -subroutine crystallite_orientations - - integer & - c, & !< counter in integration point component loop - i, & !< counter in integration point loop - e !< counter in element loop - - !$OMP PARALLEL DO - do e = FEsolving_execElem(1),FEsolving_execElem(2) - do i = FEsolving_execIP(1),FEsolving_execIP(2) - do c = 1,homogenization_Nconstituents(material_homogenizationAt(e)) - call crystallite_orientation(c,i,e)%fromMatrix(transpose(math_rotationalPart(crystallite_Fe(1:3,1:3,c,i,e)))) - enddo; enddo; enddo - !$OMP END PARALLEL DO - - nonlocalPresent: if (any(plasticState%nonlocal)) then - !$OMP PARALLEL DO - do e = FEsolving_execElem(1),FEsolving_execElem(2) - if (plasticState(material_phaseAt(1,e))%nonlocal) then - do i = FEsolving_execIP(1),FEsolving_execIP(2) - call plastic_nonlocal_updateCompatibility(crystallite_orientation, & - phase_plasticityInstance(material_phaseAt(1,e)),i,e) - enddo - endif - enddo - !$OMP END PARALLEL DO - endif nonlocalPresent - -end subroutine crystallite_orientations - - -!-------------------------------------------------------------------------------------------------- -!> @brief Map 2nd order tensor to reference config -!-------------------------------------------------------------------------------------------------- -function crystallite_push33ToRef(ipc,ip,el, tensor33) - - real(pReal), dimension(3,3) :: crystallite_push33ToRef - real(pReal), dimension(3,3), intent(in) :: tensor33 - real(pReal), dimension(3,3) :: T - integer, intent(in):: & - el, & - ip, & - ipc - - T = matmul(material_orientation0(ipc,ip,el)%asMatrix(), & ! ToDo: initial orientation correct? - transpose(math_inv33(crystallite_subF(1:3,1:3,ipc,ip,el)))) - crystallite_push33ToRef = matmul(transpose(T),matmul(tensor33,T)) - -end function crystallite_push33ToRef - - -!-------------------------------------------------------------------------------------------------- -!> @brief writes crystallite results to HDF5 output file -!-------------------------------------------------------------------------------------------------- -subroutine crystallite_results - - integer :: p,o - real(pReal), allocatable, dimension(:,:,:) :: selected_tensors - type(rotation), allocatable, dimension(:) :: selected_rotations - character(len=:), allocatable :: group,structureLabel - - do p=1,size(material_name_phase) - group = trim('current/phase')//'/'//trim(material_name_phase(p))//'/mechanics' - - call results_closeGroup(results_addGroup(group)) - - do o = 1, size(output_constituent(p)%label) - select case (output_constituent(p)%label(o)) - case('F') - selected_tensors = select_tensors(crystallite_partitionedF,p) - call results_writeDataset(group,selected_tensors,output_constituent(p)%label(o),& - 'deformation gradient','1') - case('F_e') - selected_tensors = select_tensors(crystallite_Fe,p) - call results_writeDataset(group,selected_tensors,output_constituent(p)%label(o),& - 'elastic deformation gradient','1') - case('F_p') - selected_tensors = select_tensors(crystallite_Fp,p) - call results_writeDataset(group,selected_tensors,output_constituent(p)%label(o),& - 'plastic deformation gradient','1') - case('F_i') - selected_tensors = select_tensors(crystallite_Fi,p) - call results_writeDataset(group,selected_tensors,output_constituent(p)%label(o),& - 'inelastic deformation gradient','1') - case('L_p') - selected_tensors = select_tensors(crystallite_Lp,p) - call results_writeDataset(group,selected_tensors,output_constituent(p)%label(o),& - 'plastic velocity gradient','1/s') - case('L_i') - selected_tensors = select_tensors(crystallite_Li,p) - call results_writeDataset(group,selected_tensors,output_constituent(p)%label(o),& - 'inelastic velocity gradient','1/s') - case('P') - selected_tensors = select_tensors(crystallite_P,p) - call results_writeDataset(group,selected_tensors,output_constituent(p)%label(o),& - 'First Piola-Kirchhoff stress','Pa') - case('S') - selected_tensors = select_tensors(crystallite_S,p) - call results_writeDataset(group,selected_tensors,output_constituent(p)%label(o),& - 'Second Piola-Kirchhoff stress','Pa') - case('O') - select case(lattice_structure(p)) - case(lattice_ISO_ID) - structureLabel = 'aP' - case(lattice_FCC_ID) - structureLabel = 'cF' - case(lattice_BCC_ID) - structureLabel = 'cI' - case(lattice_BCT_ID) - structureLabel = 'tI' - case(lattice_HEX_ID) - structureLabel = 'hP' - case(lattice_ORT_ID) - structureLabel = 'oP' - end select - selected_rotations = select_rotations(crystallite_orientation,p) - call results_writeDataset(group,selected_rotations,output_constituent(p)%label(o),& - 'crystal orientation as quaternion',structureLabel) - end select - enddo - enddo - - contains - - !------------------------------------------------------------------------------------------------ - !> @brief select tensors for output - !------------------------------------------------------------------------------------------------ - function select_tensors(dataset,instance) - - integer, intent(in) :: instance - real(pReal), dimension(:,:,:,:,:), intent(in) :: dataset - real(pReal), allocatable, dimension(:,:,:) :: select_tensors - integer :: e,i,c,j - - allocate(select_tensors(3,3,count(material_phaseAt==instance)*discretization_nIPs)) - - j=0 - do e = 1, size(material_phaseAt,2) - do i = 1, discretization_nIPs - do c = 1, size(material_phaseAt,1) !ToDo: this needs to be changed for varying Ngrains - if (material_phaseAt(c,e) == instance) then - j = j + 1 - select_tensors(1:3,1:3,j) = dataset(1:3,1:3,c,i,e) - endif - enddo - enddo - enddo - - end function select_tensors - - -!-------------------------------------------------------------------------------------------------- -!> @brief select rotations for output -!-------------------------------------------------------------------------------------------------- - function select_rotations(dataset,instance) - - integer, intent(in) :: instance - type(rotation), dimension(:,:,:), intent(in) :: dataset - type(rotation), allocatable, dimension(:) :: select_rotations - integer :: e,i,c,j - - allocate(select_rotations(count(material_phaseAt==instance)*homogenization_maxNconstituents*discretization_nIPs)) - - j=0 - do e = 1, size(material_phaseAt,2) - do i = 1, discretization_nIPs - do c = 1, size(material_phaseAt,1) !ToDo: this needs to be changed for varying Ngrains - if (material_phaseAt(c,e) == instance) then - j = j + 1 - select_rotations(j) = dataset(c,i,e) - endif - enddo - enddo - enddo - - end function select_rotations - -end subroutine crystallite_results - - -!-------------------------------------------------------------------------------------------------- -!> @brief calculation of stress (P) with time integration based on a residuum in Lp and -!> intermediate acceleration of the Newton-Raphson correction -!-------------------------------------------------------------------------------------------------- -function integrateStress(ipc,ip,el,timeFraction) result(broken) - - integer, intent(in):: el, & ! element index - ip, & ! integration point index - ipc ! grain index - real(pReal), optional, intent(in) :: timeFraction ! fraction of timestep - - real(pReal), dimension(3,3):: F, & ! deformation gradient at end of timestep - Fp_new, & ! plastic deformation gradient at end of timestep - invFp_new, & ! inverse of Fp_new - invFp_current, & ! inverse of Fp_current - Lpguess, & ! current guess for plastic velocity gradient - Lpguess_old, & ! known last good guess for plastic velocity gradient - Lp_constitutive, & ! plastic velocity gradient resulting from constitutive law - residuumLp, & ! current residuum of plastic velocity gradient - residuumLp_old, & ! last residuum of plastic velocity gradient - deltaLp, & ! direction of next guess - Fi_new, & ! gradient of intermediate deformation stages - invFi_new, & - invFi_current, & ! inverse of Fi_current - Liguess, & ! current guess for intermediate velocity gradient - Liguess_old, & ! known last good guess for intermediate velocity gradient - Li_constitutive, & ! intermediate velocity gradient resulting from constitutive law - residuumLi, & ! current residuum of intermediate velocity gradient - residuumLi_old, & ! last residuum of intermediate velocity gradient - deltaLi, & ! direction of next guess - Fe, & ! elastic deformation gradient - S, & ! 2nd Piola-Kirchhoff Stress in plastic (lattice) configuration - A, & - B, & - temp_33 - real(pReal), dimension(9) :: temp_9 ! needed for matrix inversion by LAPACK - integer, dimension(9) :: devNull_9 ! needed for matrix inversion by LAPACK - real(pReal), dimension(9,9) :: dRLp_dLp, & ! partial derivative of residuum (Jacobian for Newton-Raphson scheme) - dRLi_dLi ! partial derivative of residuumI (Jacobian for Newton-Raphson scheme) - real(pReal), dimension(3,3,3,3):: dS_dFe, & ! partial derivative of 2nd Piola-Kirchhoff stress - dS_dFi, & - dFe_dLp, & ! partial derivative of elastic deformation gradient - dFe_dLi, & - dFi_dLi, & - dLp_dFi, & - dLi_dFi, & - dLp_dS, & - dLi_dS - real(pReal) steplengthLp, & - steplengthLi, & - dt, & ! time increment - atol_Lp, & - atol_Li, & - devNull - integer NiterationStressLp, & ! number of stress integrations - NiterationStressLi, & ! number of inner stress integrations - ierr, & ! error indicator for LAPACK - o, & - p, & - jacoCounterLp, & - jacoCounterLi ! counters to check for Jacobian update - logical :: error,broken - - broken = .true. - - if (present(timeFraction)) then - dt = crystallite_subdt(ipc,ip,el) * timeFraction - F = crystallite_subF0(1:3,1:3,ipc,ip,el) & - + (crystallite_subF(1:3,1:3,ipc,ip,el) - crystallite_subF0(1:3,1:3,ipc,ip,el)) * timeFraction - else - dt = crystallite_subdt(ipc,ip,el) - F = crystallite_subF(1:3,1:3,ipc,ip,el) - endif - - call constitutive_dependentState(crystallite_partitionedF(1:3,1:3,ipc,ip,el), & - crystallite_Fp(1:3,1:3,ipc,ip,el),ipc,ip,el) - - Lpguess = crystallite_Lp(1:3,1:3,ipc,ip,el) ! take as first guess - Liguess = crystallite_Li(1:3,1:3,ipc,ip,el) ! take as first guess - - call math_invert33(invFp_current,devNull,error,crystallite_subFp0(1:3,1:3,ipc,ip,el)) - if (error) return ! error - call math_invert33(invFi_current,devNull,error,crystallite_subFi0(1:3,1:3,ipc,ip,el)) - if (error) return ! error - - A = matmul(F,invFp_current) ! intermediate tensor needed later to calculate dFe_dLp - - jacoCounterLi = 0 - steplengthLi = 1.0_pReal - residuumLi_old = 0.0_pReal - Liguess_old = Liguess - - NiterationStressLi = 0 - LiLoop: do - NiterationStressLi = NiterationStressLi + 1 - if (NiterationStressLi>num%nStress) return ! error - - invFi_new = matmul(invFi_current,math_I3 - dt*Liguess) - Fi_new = math_inv33(invFi_new) - - jacoCounterLp = 0 - steplengthLp = 1.0_pReal - residuumLp_old = 0.0_pReal - Lpguess_old = Lpguess - - NiterationStressLp = 0 - LpLoop: do - NiterationStressLp = NiterationStressLp + 1 - if (NiterationStressLp>num%nStress) return ! error - - B = math_I3 - dt*Lpguess - Fe = matmul(matmul(A,B), invFi_new) - call constitutive_SandItsTangents(S, dS_dFe, dS_dFi, & - Fe, Fi_new, ipc, ip, el) - - call constitutive_LpAndItsTangents(Lp_constitutive, dLp_dS, dLp_dFi, & - S, Fi_new, ipc, ip, el) - - !* update current residuum and check for convergence of loop - atol_Lp = max(num%rtol_crystalliteStress * max(norm2(Lpguess),norm2(Lp_constitutive)), & ! absolute tolerance from largest acceptable relative error - num%atol_crystalliteStress) ! minimum lower cutoff - residuumLp = Lpguess - Lp_constitutive - - if (any(IEEE_is_NaN(residuumLp))) then - return ! error - elseif (norm2(residuumLp) < atol_Lp) then ! converged if below absolute tolerance - exit LpLoop - elseif (NiterationStressLp == 1 .or. norm2(residuumLp) < norm2(residuumLp_old)) then ! not converged, but improved norm of residuum (always proceed in first iteration)... - residuumLp_old = residuumLp ! ...remember old values and... - Lpguess_old = Lpguess - steplengthLp = 1.0_pReal ! ...proceed with normal step length (calculate new search direction) - else ! not converged and residuum not improved... - steplengthLp = num%subStepSizeLp * steplengthLp ! ...try with smaller step length in same direction - Lpguess = Lpguess_old & - + deltaLp * stepLengthLp - cycle LpLoop - endif - - calculateJacobiLi: if (mod(jacoCounterLp, num%iJacoLpresiduum) == 0) then - jacoCounterLp = jacoCounterLp + 1 - - do o=1,3; do p=1,3 - dFe_dLp(o,1:3,p,1:3) = - dt * A(o,p)*transpose(invFi_new) ! dFe_dLp(i,j,k,l) = -dt * A(i,k) invFi(l,j) - enddo; enddo - dRLp_dLp = math_eye(9) & - - math_3333to99(math_mul3333xx3333(math_mul3333xx3333(dLp_dS,dS_dFe),dFe_dLp)) - temp_9 = math_33to9(residuumLp) - call dgesv(9,1,dRLp_dLp,9,devNull_9,temp_9,9,ierr) ! solve dRLp/dLp * delta Lp = -res for delta Lp - if (ierr /= 0) return ! error - deltaLp = - math_9to33(temp_9) - endif calculateJacobiLi - - Lpguess = Lpguess & - + deltaLp * steplengthLp - enddo LpLoop - - call constitutive_LiAndItsTangents(Li_constitutive, dLi_dS, dLi_dFi, & - S, Fi_new, ipc, ip, el) - - !* update current residuum and check for convergence of loop - atol_Li = max(num%rtol_crystalliteStress * max(norm2(Liguess),norm2(Li_constitutive)), & ! absolute tolerance from largest acceptable relative error - num%atol_crystalliteStress) ! minimum lower cutoff - residuumLi = Liguess - Li_constitutive - if (any(IEEE_is_NaN(residuumLi))) then - return ! error - elseif (norm2(residuumLi) < atol_Li) then ! converged if below absolute tolerance - exit LiLoop - elseif (NiterationStressLi == 1 .or. norm2(residuumLi) < norm2(residuumLi_old)) then ! not converged, but improved norm of residuum (always proceed in first iteration)... - residuumLi_old = residuumLi ! ...remember old values and... - Liguess_old = Liguess - steplengthLi = 1.0_pReal ! ...proceed with normal step length (calculate new search direction) - else ! not converged and residuum not improved... - steplengthLi = num%subStepSizeLi * steplengthLi ! ...try with smaller step length in same direction - Liguess = Liguess_old & - + deltaLi * steplengthLi - cycle LiLoop - endif - - calculateJacobiLp: if (mod(jacoCounterLi, num%iJacoLpresiduum) == 0) then - jacoCounterLi = jacoCounterLi + 1 - - temp_33 = matmul(matmul(A,B),invFi_current) - do o=1,3; do p=1,3 - dFe_dLi(1:3,o,1:3,p) = -dt*math_I3(o,p)*temp_33 ! dFe_dLp(i,j,k,l) = -dt * A(i,k) invFi(l,j) - dFi_dLi(1:3,o,1:3,p) = -dt*math_I3(o,p)*invFi_current - enddo; enddo - do o=1,3; do p=1,3 - dFi_dLi(1:3,1:3,o,p) = matmul(matmul(Fi_new,dFi_dLi(1:3,1:3,o,p)),Fi_new) - enddo; enddo - dRLi_dLi = math_eye(9) & - - math_3333to99(math_mul3333xx3333(dLi_dS, math_mul3333xx3333(dS_dFe, dFe_dLi) & - + math_mul3333xx3333(dS_dFi, dFi_dLi))) & - - math_3333to99(math_mul3333xx3333(dLi_dFi, dFi_dLi)) - temp_9 = math_33to9(residuumLi) - call dgesv(9,1,dRLi_dLi,9,devNull_9,temp_9,9,ierr) ! solve dRLi/dLp * delta Li = -res for delta Li - if (ierr /= 0) return ! error - deltaLi = - math_9to33(temp_9) - endif calculateJacobiLp - - Liguess = Liguess & - + deltaLi * steplengthLi - enddo LiLoop - - invFp_new = matmul(invFp_current,B) - call math_invert33(Fp_new,devNull,error,invFp_new) - if (error) return ! error - - crystallite_P (1:3,1:3,ipc,ip,el) = matmul(matmul(F,invFp_new),matmul(S,transpose(invFp_new))) - crystallite_S (1:3,1:3,ipc,ip,el) = S - crystallite_Lp (1:3,1:3,ipc,ip,el) = Lpguess - crystallite_Li (1:3,1:3,ipc,ip,el) = Liguess - crystallite_Fp (1:3,1:3,ipc,ip,el) = Fp_new / math_det33(Fp_new)**(1.0_pReal/3.0_pReal) ! regularize - crystallite_Fi (1:3,1:3,ipc,ip,el) = Fi_new - crystallite_Fe (1:3,1:3,ipc,ip,el) = matmul(matmul(F,invFp_new),invFi_new) - broken = .false. - -end function integrateStress - - -!-------------------------------------------------------------------------------------------------- -!> @brief integrate stress, state with adaptive 1st order explicit Euler method -!> using Fixed Point Iteration to adapt the stepsize -!-------------------------------------------------------------------------------------------------- -subroutine integrateStateFPI(g,i,e) - - integer, intent(in) :: & - e, & !< element index in element loop - i, & !< integration point index in ip loop - g !< grain index in grain loop - integer :: & - NiterationState, & !< number of iterations in state loop - p, & - c, & - s, & - size_pl - integer, dimension(maxval(phase_Nsources)) :: & - size_so - real(pReal) :: & - zeta - real(pReal), dimension(max(constitutive_plasticity_maxSizeDotState,constitutive_source_maxSizeDotState)) :: & - r ! state residuum - real(pReal), dimension(constitutive_plasticity_maxSizeDotState,2) :: & - plastic_dotState - real(pReal), dimension(constitutive_source_maxSizeDotState,2,maxval(phase_Nsources)) :: source_dotState - logical :: & - broken - - p = material_phaseAt(g,e) - c = material_phaseMemberAt(g,i,e) - - broken = constitutive_collectDotState(crystallite_S(1:3,1:3,g,i,e), & - crystallite_partitionedF0, & - crystallite_Fi(1:3,1:3,g,i,e), & - crystallite_partitionedFp0, & - crystallite_subdt(g,i,e), g,i,e,p,c) - if(broken) return - - size_pl = plasticState(p)%sizeDotState - plasticState(p)%state(1:size_pl,c) = plasticState(p)%subState0(1:size_pl,c) & - + plasticState(p)%dotState (1:size_pl,c) & - * crystallite_subdt(g,i,e) - plastic_dotState(1:size_pl,2) = 0.0_pReal - do s = 1, phase_Nsources(p) - size_so(s) = sourceState(p)%p(s)%sizeDotState - sourceState(p)%p(s)%state(1:size_so(s),c) = sourceState(p)%p(s)%subState0(1:size_so(s),c) & - + sourceState(p)%p(s)%dotState (1:size_so(s),c) & - * crystallite_subdt(g,i,e) - source_dotState(1:size_so(s),2,s) = 0.0_pReal - enddo - - iteration: do NiterationState = 1, num%nState - - if(nIterationState > 1) plastic_dotState(1:size_pl,2) = plastic_dotState(1:size_pl,1) - plastic_dotState(1:size_pl,1) = plasticState(p)%dotState(:,c) - do s = 1, phase_Nsources(p) - if(nIterationState > 1) source_dotState(1:size_so(s),2,s) = source_dotState(1:size_so(s),1,s) - source_dotState(1:size_so(s),1,s) = sourceState(p)%p(s)%dotState(:,c) - enddo - - broken = integrateStress(g,i,e) - if(broken) exit iteration - - broken = constitutive_collectDotState(crystallite_S(1:3,1:3,g,i,e), & - crystallite_partitionedF0, & - crystallite_Fi(1:3,1:3,g,i,e), & - crystallite_partitionedFp0, & - crystallite_subdt(g,i,e), g,i,e,p,c) - if(broken) exit iteration - - zeta = damper(plasticState(p)%dotState(:,c),plastic_dotState(1:size_pl,1),& - plastic_dotState(1:size_pl,2)) - plasticState(p)%dotState(:,c) = plasticState(p)%dotState(:,c) * zeta & - + plastic_dotState(1:size_pl,1) * (1.0_pReal - zeta) - r(1:size_pl) = plasticState(p)%state (1:size_pl,c) & - - plasticState(p)%subState0(1:size_pl,c) & - - plasticState(p)%dotState (1:size_pl,c) * crystallite_subdt(g,i,e) - plasticState(p)%state(1:size_pl,c) = plasticState(p)%state(1:size_pl,c) & - - r(1:size_pl) - crystallite_converged(g,i,e) = converged(r(1:size_pl), & - plasticState(p)%state(1:size_pl,c), & - plasticState(p)%atol(1:size_pl)) - do s = 1, phase_Nsources(p) - zeta = damper(sourceState(p)%p(s)%dotState(:,c), & - source_dotState(1:size_so(s),1,s),& - source_dotState(1:size_so(s),2,s)) - sourceState(p)%p(s)%dotState(:,c) = sourceState(p)%p(s)%dotState(:,c) * zeta & - + source_dotState(1:size_so(s),1,s)* (1.0_pReal - zeta) - r(1:size_so(s)) = sourceState(p)%p(s)%state (1:size_so(s),c) & - - sourceState(p)%p(s)%subState0(1:size_so(s),c) & - - sourceState(p)%p(s)%dotState (1:size_so(s),c) * crystallite_subdt(g,i,e) - sourceState(p)%p(s)%state(1:size_so(s),c) = sourceState(p)%p(s)%state(1:size_so(s),c) & - - r(1:size_so(s)) - crystallite_converged(g,i,e) = & - crystallite_converged(g,i,e) .and. converged(r(1:size_so(s)), & - sourceState(p)%p(s)%state(1:size_so(s),c), & - sourceState(p)%p(s)%atol(1:size_so(s))) - enddo - - if(crystallite_converged(g,i,e)) then - broken = constitutive_deltaState(crystallite_S(1:3,1:3,g,i,e), & - crystallite_Fe(1:3,1:3,g,i,e), & - crystallite_Fi(1:3,1:3,g,i,e),g,i,e,p,c) - exit iteration - endif - - enddo iteration - - - contains - - !-------------------------------------------------------------------------------------------------- - !> @brief calculate the damping for correction of state and dot state - !-------------------------------------------------------------------------------------------------- - real(pReal) pure function damper(current,previous,previous2) - - real(pReal), dimension(:), intent(in) ::& - current, previous, previous2 - - real(pReal) :: dot_prod12, dot_prod22 - - dot_prod12 = dot_product(current - previous, previous - previous2) - dot_prod22 = dot_product(previous - previous2, previous - previous2) - if ((dot_product(current,previous) < 0.0_pReal .or. dot_prod12 < 0.0_pReal) .and. dot_prod22 > 0.0_pReal) then - damper = 0.75_pReal + 0.25_pReal * tanh(2.0_pReal + 4.0_pReal * dot_prod12 / dot_prod22) - else - damper = 1.0_pReal - endif - - end function damper - -end subroutine integrateStateFPI - - -!-------------------------------------------------------------------------------------------------- -!> @brief integrate state with 1st order explicit Euler method -!-------------------------------------------------------------------------------------------------- -subroutine integrateStateEuler(g,i,e) - - integer, intent(in) :: & - e, & !< element index in element loop - i, & !< integration point index in ip loop - g !< grain index in grain loop - integer :: & - p, & - c, & - s, & - sizeDotState - logical :: & - broken - - p = material_phaseAt(g,e) - c = material_phaseMemberAt(g,i,e) - - broken = constitutive_collectDotState(crystallite_S(1:3,1:3,g,i,e), & - crystallite_partitionedF0, & - crystallite_Fi(1:3,1:3,g,i,e), & - crystallite_partitionedFp0, & - crystallite_subdt(g,i,e), g,i,e,p,c) - if(broken) return - - sizeDotState = plasticState(p)%sizeDotState - plasticState(p)%state(1:sizeDotState,c) = plasticState(p)%subState0(1:sizeDotState,c) & - + plasticState(p)%dotState (1:sizeDotState,c) & - * crystallite_subdt(g,i,e) - do s = 1, phase_Nsources(p) - sizeDotState = sourceState(p)%p(s)%sizeDotState - sourceState(p)%p(s)%state(1:sizeDotState,c) = sourceState(p)%p(s)%subState0(1:sizeDotState,c) & - + sourceState(p)%p(s)%dotState (1:sizeDotState,c) & - * crystallite_subdt(g,i,e) - enddo - - broken = constitutive_deltaState(crystallite_S(1:3,1:3,g,i,e), & - crystallite_Fe(1:3,1:3,g,i,e), & - crystallite_Fi(1:3,1:3,g,i,e),g,i,e,p,c) - if(broken) return - - broken = integrateStress(g,i,e) - crystallite_converged(g,i,e) = .not. broken - -end subroutine integrateStateEuler - - -!-------------------------------------------------------------------------------------------------- -!> @brief integrate stress, state with 1st order Euler method with adaptive step size -!-------------------------------------------------------------------------------------------------- -subroutine integrateStateAdaptiveEuler(g,i,e) - - integer, intent(in) :: & - e, & !< element index in element loop - i, & !< integration point index in ip loop - g !< grain index in grain loop - integer :: & - p, & - c, & - s, & - sizeDotState - logical :: & - broken - - real(pReal), dimension(constitutive_plasticity_maxSizeDotState) :: residuum_plastic - real(pReal), dimension(constitutive_source_maxSizeDotState,maxval(phase_Nsources)) :: residuum_source - - - p = material_phaseAt(g,e) - c = material_phaseMemberAt(g,i,e) - - broken = constitutive_collectDotState(crystallite_S(1:3,1:3,g,i,e), & - crystallite_partitionedF0, & - crystallite_Fi(1:3,1:3,g,i,e), & - crystallite_partitionedFp0, & - crystallite_subdt(g,i,e), g,i,e,p,c) - if(broken) return - - sizeDotState = plasticState(p)%sizeDotState - - residuum_plastic(1:sizeDotState) = - plasticState(p)%dotstate(1:sizeDotState,c) * 0.5_pReal * crystallite_subdt(g,i,e) - plasticState(p)%state(1:sizeDotState,c) = plasticState(p)%subState0(1:sizeDotState,c) & - + plasticState(p)%dotstate(1:sizeDotState,c) * crystallite_subdt(g,i,e) - do s = 1, phase_Nsources(p) - sizeDotState = sourceState(p)%p(s)%sizeDotState - - residuum_source(1:sizeDotState,s) = - sourceState(p)%p(s)%dotstate(1:sizeDotState,c) & - * 0.5_pReal * crystallite_subdt(g,i,e) - sourceState(p)%p(s)%state(1:sizeDotState,c) = sourceState(p)%p(s)%subState0(1:sizeDotState,c) & - + sourceState(p)%p(s)%dotstate(1:sizeDotState,c) * crystallite_subdt(g,i,e) - enddo - - broken = constitutive_deltaState(crystallite_S(1:3,1:3,g,i,e), & - crystallite_Fe(1:3,1:3,g,i,e), & - crystallite_Fi(1:3,1:3,g,i,e),g,i,e,p,c) - if(broken) return - - broken = integrateStress(g,i,e) - if(broken) return - - broken = constitutive_collectDotState(crystallite_S(1:3,1:3,g,i,e), & - crystallite_partitionedF0, & - crystallite_Fi(1:3,1:3,g,i,e), & - crystallite_partitionedFp0, & - crystallite_subdt(g,i,e), g,i,e,p,c) - if(broken) return - - - sizeDotState = plasticState(p)%sizeDotState - crystallite_converged(g,i,e) = converged(residuum_plastic(1:sizeDotState) & - + 0.5_pReal * plasticState(p)%dotState(:,c) * crystallite_subdt(g,i,e), & - plasticState(p)%state(1:sizeDotState,c), & - plasticState(p)%atol(1:sizeDotState)) - - do s = 1, phase_Nsources(p) - sizeDotState = sourceState(p)%p(s)%sizeDotState - crystallite_converged(g,i,e) = & - crystallite_converged(g,i,e) .and. converged(residuum_source(1:sizeDotState,s) & - + 0.5_pReal*sourceState(p)%p(s)%dotState(:,c)*crystallite_subdt(g,i,e), & - sourceState(p)%p(s)%state(1:sizeDotState,c), & - sourceState(p)%p(s)%atol(1:sizeDotState)) - enddo - -end subroutine integrateStateAdaptiveEuler - - -!--------------------------------------------------------------------------------------------------- -!> @brief Integrate state (including stress integration) with the classic Runge Kutta method -!--------------------------------------------------------------------------------------------------- -subroutine integrateStateRK4(g,i,e) - - integer, intent(in) :: g,i,e - - real(pReal), dimension(3,3), parameter :: & - A = reshape([& - 0.5_pReal, 0.0_pReal, 0.0_pReal, & - 0.0_pReal, 0.5_pReal, 0.0_pReal, & - 0.0_pReal, 0.0_pReal, 1.0_pReal],& - shape(A)) - real(pReal), dimension(3), parameter :: & - C = [0.5_pReal, 0.5_pReal, 1.0_pReal] - real(pReal), dimension(4), parameter :: & - B = [1.0_pReal/6.0_pReal, 1.0_pReal/3.0_pReal, 1.0_pReal/3.0_pReal, 1.0_pReal/6.0_pReal] - - call integrateStateRK(g,i,e,A,B,C) - -end subroutine integrateStateRK4 - - -!--------------------------------------------------------------------------------------------------- -!> @brief Integrate state (including stress integration) with the Cash-Carp method -!--------------------------------------------------------------------------------------------------- -subroutine integrateStateRKCK45(g,i,e) - - integer, intent(in) :: g,i,e - - real(pReal), dimension(5,5), parameter :: & - A = reshape([& - 1._pReal/5._pReal, .0_pReal, .0_pReal, .0_pReal, .0_pReal, & - 3._pReal/40._pReal, 9._pReal/40._pReal, .0_pReal, .0_pReal, .0_pReal, & - 3_pReal/10._pReal, -9._pReal/10._pReal, 6._pReal/5._pReal, .0_pReal, .0_pReal, & - -11._pReal/54._pReal, 5._pReal/2._pReal, -70.0_pReal/27.0_pReal, 35.0_pReal/27.0_pReal, .0_pReal, & - 1631._pReal/55296._pReal,175._pReal/512._pReal,575._pReal/13824._pReal,44275._pReal/110592._pReal,253._pReal/4096._pReal],& - shape(A)) - real(pReal), dimension(5), parameter :: & - C = [0.2_pReal, 0.3_pReal, 0.6_pReal, 1.0_pReal, 0.875_pReal] - real(pReal), dimension(6), parameter :: & - B = & - [37.0_pReal/378.0_pReal, .0_pReal, 250.0_pReal/621.0_pReal, & - 125.0_pReal/594.0_pReal, .0_pReal, 512.0_pReal/1771.0_pReal], & - DB = B - & - [2825.0_pReal/27648.0_pReal, .0_pReal, 18575.0_pReal/48384.0_pReal,& - 13525.0_pReal/55296.0_pReal, 277.0_pReal/14336.0_pReal, 1._pReal/4._pReal] - - call integrateStateRK(g,i,e,A,B,C,DB) - -end subroutine integrateStateRKCK45 - - -!-------------------------------------------------------------------------------------------------- -!> @brief Integrate state (including stress integration) with an explicit Runge-Kutta method or an -!! embedded explicit Runge-Kutta method -!-------------------------------------------------------------------------------------------------- -subroutine integrateStateRK(g,i,e,A,B,CC,DB) - - - real(pReal), dimension(:,:), intent(in) :: A - real(pReal), dimension(:), intent(in) :: B, CC - real(pReal), dimension(:), intent(in), optional :: DB - - integer, intent(in) :: & - e, & !< element index in element loop - i, & !< integration point index in ip loop - g !< grain index in grain loop - integer :: & - stage, & ! stage index in integration stage loop - n, & - p, & - c, & - s, & - sizeDotState - logical :: & - broken - real(pReal), dimension(constitutive_source_maxSizeDotState,size(B),maxval(phase_Nsources)) :: source_RKdotState - real(pReal), dimension(constitutive_plasticity_maxSizeDotState,size(B)) :: plastic_RKdotState - - p = material_phaseAt(g,e) - c = material_phaseMemberAt(g,i,e) - - broken = constitutive_collectDotState(crystallite_S(1:3,1:3,g,i,e), & - crystallite_partitionedF0, & - crystallite_Fi(1:3,1:3,g,i,e), & - crystallite_partitionedFp0, & - crystallite_subdt(g,i,e), g,i,e,p,c) - if(broken) return - - do stage = 1,size(A,1) - sizeDotState = plasticState(p)%sizeDotState - plastic_RKdotState(1:sizeDotState,stage) = plasticState(p)%dotState(:,c) - plasticState(p)%dotState(:,c) = A(1,stage) * plastic_RKdotState(1:sizeDotState,1) - do s = 1, phase_Nsources(p) - sizeDotState = sourceState(p)%p(s)%sizeDotState - source_RKdotState(1:sizeDotState,stage,s) = sourceState(p)%p(s)%dotState(:,c) - sourceState(p)%p(s)%dotState(:,c) = A(1,stage) * source_RKdotState(1:sizeDotState,1,s) - enddo - - do n = 2, stage - sizeDotState = plasticState(p)%sizeDotState - plasticState(p)%dotState(:,c) = plasticState(p)%dotState(:,c) & - + A(n,stage) * plastic_RKdotState(1:sizeDotState,n) - do s = 1, phase_Nsources(p) - sizeDotState = sourceState(p)%p(s)%sizeDotState - sourceState(p)%p(s)%dotState(:,c) = sourceState(p)%p(s)%dotState(:,c) & - + A(n,stage) * source_RKdotState(1:sizeDotState,n,s) - enddo - enddo - - sizeDotState = plasticState(p)%sizeDotState - plasticState(p)%state(1:sizeDotState,c) = plasticState(p)%subState0(1:sizeDotState,c) & - + plasticState(p)%dotState (1:sizeDotState,c) & - * crystallite_subdt(g,i,e) - do s = 1, phase_Nsources(p) - sizeDotState = sourceState(p)%p(s)%sizeDotState - sourceState(p)%p(s)%state(1:sizeDotState,c) = sourceState(p)%p(s)%subState0(1:sizeDotState,c) & - + sourceState(p)%p(s)%dotState (1:sizeDotState,c) & - * crystallite_subdt(g,i,e) - enddo - - broken = integrateStress(g,i,e,CC(stage)) - if(broken) exit - - broken = constitutive_collectDotState(crystallite_S(1:3,1:3,g,i,e), & - crystallite_partitionedF0, & - crystallite_Fi(1:3,1:3,g,i,e), & - crystallite_partitionedFp0, & - crystallite_subdt(g,i,e)*CC(stage), g,i,e,p,c) - if(broken) exit - - enddo - if(broken) return - - sizeDotState = plasticState(p)%sizeDotState - - plastic_RKdotState(1:sizeDotState,size(B)) = plasticState (p)%dotState(:,c) - plasticState(p)%dotState(:,c) = matmul(plastic_RKdotState(1:sizeDotState,1:size(B)),B) - plasticState(p)%state(1:sizeDotState,c) = plasticState(p)%subState0(1:sizeDotState,c) & - + plasticState(p)%dotState (1:sizeDotState,c) & - * crystallite_subdt(g,i,e) - if(present(DB)) & - broken = .not. converged( matmul(plastic_RKdotState(1:sizeDotState,1:size(DB)),DB) & - * crystallite_subdt(g,i,e), & - plasticState(p)%state(1:sizeDotState,c), & - plasticState(p)%atol(1:sizeDotState)) - - do s = 1, phase_Nsources(p) - sizeDotState = sourceState(p)%p(s)%sizeDotState - - source_RKdotState(1:sizeDotState,size(B),s) = sourceState(p)%p(s)%dotState(:,c) - sourceState(p)%p(s)%dotState(:,c) = matmul(source_RKdotState(1:sizeDotState,1:size(B),s),B) - sourceState(p)%p(s)%state(1:sizeDotState,c) = sourceState(p)%p(s)%subState0(1:sizeDotState,c) & - + sourceState(p)%p(s)%dotState (1:sizeDotState,c) & - * crystallite_subdt(g,i,e) - if(present(DB)) & - broken = broken .or. .not. converged(matmul(source_RKdotState(1:sizeDotState,1:size(DB),s),DB) & - * crystallite_subdt(g,i,e), & - sourceState(p)%p(s)%state(1:sizeDotState,c), & - sourceState(p)%p(s)%atol(1:sizeDotState)) - enddo - if(broken) return - - broken = constitutive_deltaState(crystallite_S(1:3,1:3,g,i,e), & - crystallite_Fe(1:3,1:3,g,i,e), & - crystallite_Fi(1:3,1:3,g,i,e),g,i,e,p,c) - if(broken) return - - broken = integrateStress(g,i,e) - crystallite_converged(g,i,e) = .not. broken - - -end subroutine integrateStateRK - - -!-------------------------------------------------------------------------------------------------- -!> @brief determines whether a point is converged -!-------------------------------------------------------------------------------------------------- -logical pure function converged(residuum,state,atol) - - real(pReal), intent(in), dimension(:) ::& - residuum, state, atol - real(pReal) :: & - rTol - - rTol = num%rTol_crystalliteState - - converged = all(abs(residuum) <= max(atol, rtol*abs(state))) - -end function converged - - -!-------------------------------------------------------------------------------------------------- -!> @brief Write current restart information (Field and constitutive data) to file. -! ToDo: Merge data into one file for MPI, move state to constitutive and homogenization, respectively -!-------------------------------------------------------------------------------------------------- -subroutine crystallite_restartWrite - - integer :: i - integer(HID_T) :: fileHandle, groupHandle - character(len=pStringLen) :: fileName, datasetName - - print*, ' writing field and constitutive data required for restart to file';flush(IO_STDOUT) - - write(fileName,'(a,i0,a)') trim(getSolverJobName())//'_',worldrank,'.hdf5' - fileHandle = HDF5_openFile(fileName,'a') - - call HDF5_write(fileHandle,crystallite_partitionedF,'F') - call HDF5_write(fileHandle,crystallite_Fp, 'F_p') - call HDF5_write(fileHandle,crystallite_Fi, 'F_i') - call HDF5_write(fileHandle,crystallite_Lp, 'L_p') - call HDF5_write(fileHandle,crystallite_Li, 'L_i') - call HDF5_write(fileHandle,crystallite_S, 'S') - - groupHandle = HDF5_addGroup(fileHandle,'phase') - do i = 1,size(material_name_phase) - write(datasetName,'(i0,a)') i,'_omega' - call HDF5_write(groupHandle,plasticState(i)%state,datasetName) - enddo - call HDF5_closeGroup(groupHandle) - - groupHandle = HDF5_addGroup(fileHandle,'homogenization') - do i = 1, size(material_name_homogenization) - write(datasetName,'(i0,a)') i,'_omega' - call HDF5_write(groupHandle,homogState(i)%state,datasetName) - enddo - call HDF5_closeGroup(groupHandle) - - call HDF5_closeFile(fileHandle) - -end subroutine crystallite_restartWrite - - -!-------------------------------------------------------------------------------------------------- -!> @brief Read data for restart -! ToDo: Merge data into one file for MPI, move state to constitutive and homogenization, respectively -!-------------------------------------------------------------------------------------------------- -subroutine crystallite_restartRead - - integer :: i - integer(HID_T) :: fileHandle, groupHandle - character(len=pStringLen) :: fileName, datasetName - - print'(/,a,i0,a)', ' reading restart information of increment from file' - - write(fileName,'(a,i0,a)') trim(getSolverJobName())//'_',worldrank,'.hdf5' - fileHandle = HDF5_openFile(fileName) - - call HDF5_read(fileHandle,crystallite_F0, 'F') - call HDF5_read(fileHandle,crystallite_Fp0,'F_p') - call HDF5_read(fileHandle,crystallite_Fi0,'F_i') - call HDF5_read(fileHandle,crystallite_Lp0,'L_p') - call HDF5_read(fileHandle,crystallite_Li0,'L_i') - call HDF5_read(fileHandle,crystallite_S0, 'S') - - groupHandle = HDF5_openGroup(fileHandle,'phase') - do i = 1,size(material_name_phase) - write(datasetName,'(i0,a)') i,'_omega' - call HDF5_read(groupHandle,plasticState(i)%state0,datasetName) - enddo - call HDF5_closeGroup(groupHandle) - - groupHandle = HDF5_openGroup(fileHandle,'homogenization') - do i = 1,size(material_name_homogenization) - write(datasetName,'(i0,a)') i,'_omega' - call HDF5_read(groupHandle,homogState(i)%state0,datasetName) - enddo - call HDF5_closeGroup(groupHandle) - - call HDF5_closeFile(fileHandle) - -end subroutine crystallite_restartRead - - -!-------------------------------------------------------------------------------------------------- -!> @brief Forward data after successful increment. -! ToDo: Any guessing for the current states possible? -!-------------------------------------------------------------------------------------------------- -subroutine crystallite_forward - - integer :: i, j - - crystallite_F0 = crystallite_partitionedF - crystallite_Fp0 = crystallite_Fp - crystallite_Lp0 = crystallite_Lp - crystallite_Fi0 = crystallite_Fi - crystallite_Li0 = crystallite_Li - crystallite_S0 = crystallite_S - - do i = 1, size(plasticState) - plasticState(i)%state0 = plasticState(i)%state - enddo - do i = 1, size(sourceState) - do j = 1,phase_Nsources(i) - sourceState(i)%p(j)%state0 = sourceState(i)%p(j)%state - enddo; enddo - do i = 1,size(material_name_homogenization) - homogState (i)%state0 = homogState (i)%state - thermalState(i)%state0 = thermalState(i)%state - damageState (i)%state0 = damageState (i)%state - enddo - -end subroutine crystallite_forward - -end module crystallite diff --git a/src/damage_local.f90 b/src/damage_local.f90 deleted file mode 100644 index e63db90b0..000000000 --- a/src/damage_local.f90 +++ /dev/null @@ -1,175 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH -!> @brief material subroutine for locally evolving damage field -!-------------------------------------------------------------------------------------------------- -module damage_local - use prec - use IO - use material - use config - use YAML_types - use constitutive - use results - - implicit none - private - - type :: tParameters - character(len=pStringLen), allocatable, dimension(:) :: & - output - end type tParameters - - type, private :: tNumerics - real(pReal) :: & - residualStiffness !< non-zero residual damage - end type tNumerics - - type(tparameters), dimension(:), allocatable :: & - param - - type(tNumerics), private :: num - - public :: & - damage_local_init, & - damage_local_updateState, & - damage_local_results - -contains - -!-------------------------------------------------------------------------------------------------- -!> @brief module initialization -!> @details reads in material parameters, allocates arrays, and does sanity checks -!-------------------------------------------------------------------------------------------------- -subroutine damage_local_init - - integer :: Ninstances,Nmaterialpoints,h - class(tNode), pointer :: & - num_generic, & - material_homogenization, & - homog, & - homogDamage - - print'(/,a)', ' <<<+- damage_local init -+>>>'; flush(IO_STDOUT) - -!---------------------------------------------------------------------------------------------- -! read numerics parameter and do sanity check - num_generic => config_numerics%get('generic',defaultVal=emptyDict) - num%residualStiffness = num_generic%get_asFloat('residualStiffness', defaultVal=1.0e-6_pReal) - if (num%residualStiffness < 0.0_pReal) call IO_error(301,ext_msg='residualStiffness') - - Ninstances = count(damage_type == DAMAGE_local_ID) - allocate(param(Ninstances)) - - material_homogenization => config_material%get('homogenization') - do h = 1, material_homogenization%length - if (damage_type(h) /= DAMAGE_LOCAL_ID) cycle - homog => material_homogenization%get(h) - homogDamage => homog%get('damage') - associate(prm => param(damage_typeInstance(h))) - -#if defined (__GFORTRAN__) - prm%output = output_asStrings(homogDamage) -#else - prm%output = homogDamage%get_asStrings('output',defaultVal=emptyStringArray) -#endif - - Nmaterialpoints = count(material_homogenizationAt == h) - damageState(h)%sizeState = 1 - allocate(damageState(h)%state0 (1,Nmaterialpoints), source=damage_initialPhi(h)) - allocate(damageState(h)%subState0(1,Nmaterialpoints), source=damage_initialPhi(h)) - allocate(damageState(h)%state (1,Nmaterialpoints), source=damage_initialPhi(h)) - - nullify(damageMapping(h)%p) - damageMapping(h)%p => material_homogenizationMemberAt - deallocate(damage(h)%p) - damage(h)%p => damageState(h)%state(1,:) - - end associate - enddo - -end subroutine damage_local_init - - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates local change in damage field -!-------------------------------------------------------------------------------------------------- -function damage_local_updateState(subdt, ip, el) - - integer, intent(in) :: & - ip, & !< integration point number - el !< element number - real(pReal), intent(in) :: & - subdt - logical, dimension(2) :: & - damage_local_updateState - integer :: & - homog, & - offset - real(pReal) :: & - phi, phiDot, dPhiDot_dPhi - - homog = material_homogenizationAt(el) - offset = material_homogenizationMemberAt(ip,el) - phi = damageState(homog)%subState0(1,offset) - call damage_local_getSourceAndItsTangent(phiDot, dPhiDot_dPhi, phi, ip, el) - phi = max(num%residualStiffness,min(1.0_pReal,phi + subdt*phiDot)) - - damage_local_updateState = [ abs(phi - damageState(homog)%state(1,offset)) & - <= 1.0e-2_pReal & - .or. abs(phi - damageState(homog)%state(1,offset)) & - <= 1.0e-6_pReal*abs(damageState(homog)%state(1,offset)), & - .true.] - - damageState(homog)%state(1,offset) = phi - -end function damage_local_updateState - - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates homogenized local damage driving forces -!-------------------------------------------------------------------------------------------------- -subroutine damage_local_getSourceAndItsTangent(phiDot, dPhiDot_dPhi, phi, ip, el) - - integer, intent(in) :: & - ip, & !< integration point number - el !< element number - real(pReal), intent(in) :: & - phi - real(pReal) :: & - phiDot, dPhiDot_dPhi - - phiDot = 0.0_pReal - dPhiDot_dPhi = 0.0_pReal - - call constitutive_damage_getRateAndItsTangents(phiDot, dPhiDot_dPhi, phi, ip, el) - - phiDot = phiDot/real(homogenization_Nconstituents(material_homogenizationAt(el)),pReal) - dPhiDot_dPhi = dPhiDot_dPhi/real(homogenization_Nconstituents(material_homogenizationAt(el)),pReal) - -end subroutine damage_local_getSourceAndItsTangent - - -!-------------------------------------------------------------------------------------------------- -!> @brief writes results to HDF5 output file -!-------------------------------------------------------------------------------------------------- -subroutine damage_local_results(homog,group) - - integer, intent(in) :: homog - character(len=*), intent(in) :: group - - integer :: o - - associate(prm => param(damage_typeInstance(homog))) - outputsLoop: do o = 1,size(prm%output) - select case(prm%output(o)) - case ('phi') - call results_writeDataset(group,damage(homog)%p,prm%output(o),& - 'damage indicator','-') - end select - enddo outputsLoop - end associate - -end subroutine damage_local_results - - -end module damage_local diff --git a/src/damage_none.f90 b/src/damage_none.f90 index 2279bc06b..3f1144833 100644 --- a/src/damage_none.f90 +++ b/src/damage_none.f90 @@ -3,6 +3,7 @@ !> @brief material subroutine for constant damage field !-------------------------------------------------------------------------------------------------- module damage_none + use prec use config use material @@ -29,8 +30,7 @@ subroutine damage_none_init allocate(damageState(h)%subState0(0,Nmaterialpoints)) allocate(damageState(h)%state (0,Nmaterialpoints)) - deallocate(damage(h)%p) - allocate (damage(h)%p(1), source=damage_initialPhi(h)) + allocate (damage(h)%p(Nmaterialpoints), source=1.0_pReal) enddo diff --git a/src/damage_nonlocal.f90 b/src/damage_nonlocal.f90 index 24a51cf54..3db63cab2 100644 --- a/src/damage_nonlocal.f90 +++ b/src/damage_nonlocal.f90 @@ -7,7 +7,6 @@ module damage_nonlocal use material use config use YAML_types - use crystallite use lattice use constitutive use results @@ -78,13 +77,10 @@ subroutine damage_nonlocal_init Nmaterialpoints = count(material_homogenizationAt == h) damageState(h)%sizeState = 1 - allocate(damageState(h)%state0 (1,Nmaterialpoints), source=damage_initialPhi(h)) - allocate(damageState(h)%subState0(1,Nmaterialpoints), source=damage_initialPhi(h)) - allocate(damageState(h)%state (1,Nmaterialpoints), source=damage_initialPhi(h)) + allocate(damageState(h)%state0 (1,Nmaterialpoints), source=1.0_pReal) + allocate(damageState(h)%subState0(1,Nmaterialpoints), source=1.0_pReal) + allocate(damageState(h)%state (1,Nmaterialpoints), source=1.0_pReal) - nullify(damageMapping(h)%p) - damageMapping(h)%p => material_homogenizationMemberAt - deallocate(damage(h)%p) damage(h)%p => damageState(h)%state(1,:) end associate @@ -152,12 +148,12 @@ real(pReal) function damage_nonlocal_getMobility(ip,el) ip, & !< integration point number el !< element number integer :: & - ipc + co damage_nonlocal_getMobility = 0.0_pReal - do ipc = 1, homogenization_Nconstituents(material_homogenizationAt(el)) - damage_nonlocal_getMobility = damage_nonlocal_getMobility + lattice_M(material_phaseAt(ipc,el)) + do co = 1, homogenization_Nconstituents(material_homogenizationAt(el)) + damage_nonlocal_getMobility = damage_nonlocal_getMobility + lattice_M(material_phaseAt(co,el)) enddo damage_nonlocal_getMobility = damage_nonlocal_getMobility/& @@ -181,7 +177,7 @@ subroutine damage_nonlocal_putNonLocalDamage(phi,ip,el) offset homog = material_homogenizationAt(el) - offset = damageMapping(homog)%p(ip,el) + offset = material_homogenizationMemberAt(ip,el) damage(homog)%p(offset) = phi end subroutine damage_nonlocal_putNonLocalDamage diff --git a/src/discretization.f90 b/src/discretization.f90 index 0b8925e4a..2b19cb20b 100644 --- a/src/discretization.f90 +++ b/src/discretization.f90 @@ -86,7 +86,7 @@ subroutine discretization_results u = discretization_IPcoords & - discretization_IPcoords0 - call results_writeDataset('current/geometry',u,'u_p','displacements of the materialpoints','m') + call results_writeDataset('current/geometry',u,'u_p','displacements of the materialpoints (cell centers)','m') end subroutine discretization_results diff --git a/src/grid/DAMASK_grid.f90 b/src/grid/DAMASK_grid.f90 index a8271cffc..514443dbb 100644 --- a/src/grid/DAMASK_grid.f90 +++ b/src/grid/DAMASK_grid.f90 @@ -42,8 +42,8 @@ program DAMASK_grid !-------------------------------------------------------------------------------------------------- ! variables related to information from load case and geom file - real(pReal), dimension(9) :: temp_valueVector = 0.0_pReal !< temporarily from loadcase file when reading in tensors (initialize to 0.0) - logical, dimension(9) :: temp_maskVector = .false. !< temporarily from loadcase file when reading in tensors + real(pReal), dimension(9) :: temp_valueVector !< temporarily from loadcase file when reading in tensors (initialize to 0.0) + logical, dimension(9) :: temp_maskVector !< temporarily from loadcase file when reading in tensors !-------------------------------------------------------------------------------------------------- ! loop variables, convergence etc. @@ -143,8 +143,6 @@ program DAMASK_grid mech_restartWrite => grid_mech_spectral_basic_restartWrite case ('Polarisation') - if(debug_grid%contains('basic')) & - call IO_warning(42, ext_msg='debug Divergence') mech_init => grid_mech_spectral_polarisation_init mech_forward => grid_mech_spectral_polarisation_forward mech_solution => grid_mech_spectral_polarisation_solution @@ -152,8 +150,6 @@ program DAMASK_grid mech_restartWrite => grid_mech_spectral_polarisation_restartWrite case ('FEM') - if(debug_grid%contains('basic')) & - call IO_warning(42, ext_msg='debug Divergence') mech_init => grid_mech_FEM_init mech_forward => grid_mech_FEM_forward mech_solution => grid_mech_FEM_solution @@ -178,11 +174,11 @@ program DAMASK_grid allocate(loadCases(l)%ID(nActiveFields)) field = 1 loadCases(l)%ID(field) = FIELD_MECH_ID ! mechanical active by default - thermalActive: if (any(thermal_type == THERMAL_conduction_ID)) then + thermalActive: if (any(thermal_type == THERMAL_conduction_ID)) then field = field + 1 loadCases(l)%ID(field) = FIELD_THERMAL_ID endif thermalActive - damageActive: if (any(damage_type == DAMAGE_nonlocal_ID)) then + damageActive: if (any(damage_type == DAMAGE_nonlocal_ID)) then field = field + 1 loadCases(l)%ID(field) = FIELD_DAMAGE_ID endif damageActive @@ -190,33 +186,35 @@ program DAMASK_grid load_step => load_steps%get(l) step_mech => load_step%get('mechanics') - loadCases(l)%stress%myType='P' + loadCases(l)%stress%myType='' readMech: do m = 1, step_mech%length select case (step_mech%getKey(m)) - case('dot_F','L','F') ! assign values for the deformation BC matrix + case ('L','dot_F','F') ! assign values for the deformation BC matrix loadCases(l)%deformation%myType = step_mech%getKey(m) - temp_valueVector = 0.0_pReal - step_deformation => step_mech%get(m) - do j = 1, 9 - temp_maskVector(j) = step_deformation%get_asString(j) /= 'x' ! true if not a 'x' - if (temp_maskVector(j)) temp_valueVector(j) = step_deformation%get_asFloat(j) ! read value where applicable - enddo - loadCases(l)%deformation%mask = transpose(reshape(temp_maskVector,[ 3,3])) ! mask in 3x3 notation - loadCases(l)%deformation%values = math_9to33(temp_valueVector) ! values in 3x3 notation - case('P') + temp_valueVector = 0.0_pReal - step_stress => step_mech%get(m) do j = 1, 9 - temp_maskVector(j) = step_stress%get_asString(j) /= 'x' ! true if not a 'x' - if (temp_maskVector(j)) temp_valueVector(j) = step_stress%get_asFloat(j) ! read value where applicable + temp_maskVector(j) = step_deformation%get_asString(j) /= 'x' + if (temp_maskVector(j)) temp_valueVector(j) = step_deformation%get_asFloat(j) enddo - loadCases(l)%stress%mask = transpose(reshape(temp_maskVector,[ 3,3])) + loadCases(l)%deformation%mask = transpose(reshape(temp_maskVector,[3,3])) + loadCases(l)%deformation%values = math_9to33(temp_valueVector) + case ('dot_P','P') + loadCases(l)%stress%myType = step_mech%getKey(m) + step_stress => step_mech%get(m) + + temp_valueVector = 0.0_pReal + do j = 1, 9 + temp_maskVector(j) = step_stress%get_asString(j) /= 'x' + if (temp_maskVector(j)) temp_valueVector(j) = step_stress%get_asFloat(j) + enddo + loadCases(l)%stress%mask = transpose(reshape(temp_maskVector,[3,3])) loadCases(l)%stress%values = math_9to33(temp_valueVector) end select call loadCases(l)%rot%fromAxisAngle(step_mech%get_asFloats('R',defaultVal = real([0.0,0.0,1.0,0.0],pReal)),degrees=.true.) enddo readMech - if (.not. allocated(loadCases(l)%deformation%myType)) call IO_error(error_ID=837,ext_msg = 'L/F/dot_F missing') + if (.not. allocated(loadCases(l)%deformation%myType)) call IO_error(error_ID=837,ext_msg = 'L/dot_F/F missing') step_discretization => load_step%get('discretization') if(.not. step_discretization%contains('t')) call IO_error(error_ID=837,ext_msg = 't missing') @@ -239,50 +237,60 @@ program DAMASK_grid if (any(loadCases(l)%deformation%mask(j,1:3) .eqv. .true.) .and. & any(loadCases(l)%deformation%mask(j,1:3) .eqv. .false.)) errorID = 832 ! each row should be either fully or not at all defined enddo - print*, ' L:' - else if (loadCases(l)%deformation%myType == 'F') then + endif + if (loadCases(l)%deformation%myType == 'F') then print*, ' F:' - else if (loadCases(l)%deformation%myType == 'dot_F') then - print*, ' dot_F:' + else + print*, ' '//loadCases(l)%deformation%myType//' / 1/s:' endif do i = 1, 3; do j = 1, 3 - if(loadCases(l)%deformation%mask(i,j)) then + if (loadCases(l)%deformation%mask(i,j)) then write(IO_STDOUT,'(2x,f12.7)',advance='no') loadCases(l)%deformation%values(i,j) - else - write(IO_STDOUT,'(2x,12a)',advance='no') ' x ' - endif - enddo; write(IO_STDOUT,'(/)',advance='no') - enddo - if (any(loadCases(l)%stress%mask .eqv. loadCases(l)%deformation%mask)) errorID = 831 ! exclusive or masking only - if (any(loadCases(l)%stress%mask .and. transpose(loadCases(l)%stress%mask) .and. (math_I3<1))) & - errorID = 838 ! no rotation is allowed by stress BC - print*, ' P / MPa:' - do i = 1, 3; do j = 1, 3 - if(loadCases(l)%stress%mask(i,j)) then - write(IO_STDOUT,'(2x,f12.4)',advance='no') loadCases(l)%stress%values(i,j)*1e-6_pReal else write(IO_STDOUT,'(2x,12a)',advance='no') ' x ' endif enddo; write(IO_STDOUT,'(/)',advance='no') enddo + if (any(loadCases(l)%stress%mask .eqv. loadCases(l)%deformation%mask)) errorID = 831 + if (any(loadCases(l)%stress%mask .and. transpose(loadCases(l)%stress%mask) .and. (math_I3<1))) & + errorID = 838 ! no rotation is allowed by stress BC + + if (loadCases(l)%stress%myType == 'P') print*, ' P / MPa:' + if (loadCases(l)%stress%myType == 'dot_P') print*, ' dot_P / MPa/s:' + + if (loadCases(l)%stress%myType /= '') then + do i = 1, 3; do j = 1, 3 + if (loadCases(l)%stress%mask(i,j)) then + write(IO_STDOUT,'(2x,f12.4)',advance='no') loadCases(l)%stress%values(i,j)*1e-6_pReal + else + write(IO_STDOUT,'(2x,12a)',advance='no') ' x ' + endif + enddo; write(IO_STDOUT,'(/)',advance='no') + enddo + endif if (any(dNeq(loadCases(l)%rot%asMatrix(), math_I3))) & write(IO_STDOUT,'(2x,a,/,3(3(3x,f12.7,1x)/))',advance='no') 'R:',& transpose(loadCases(l)%rot%asMatrix()) - if (loadCases(l)%t < 0.0_pReal) errorID = 834 - print'(a,f0.3)', ' t: ', loadCases(l)%t - if (loadCases(l)%N < 1) errorID = 835 - print'(a,i0)', ' N: ', loadCases(l)%N - if (loadCases(l)%f_out < 1) errorID = 836 - print'(a,i0)', ' f_out: ', loadCases(l)%f_out - if (loadCases(l)%r <= 0.0) errorID = 833 - print'(a,f0.3)', ' r: ', loadCases(l)%r - + if (loadCases(l)%r <= 0.0) errorID = 833 + if (loadCases(l)%t < 0.0_pReal) errorID = 834 + if (loadCases(l)%N < 1) errorID = 835 + if (loadCases(l)%f_out < 1) errorID = 836 if (loadCases(l)%f_restart < 1) errorID = 839 + + if (dEq(loadCases(l)%r,1.0_pReal,1.e-9_pReal)) then + print'(a)', ' r: 1 (constant step widths)' + else + print'(a,f0.3)', ' r: ', loadCases(l)%r + endif + print'(a,f0.3)', ' t: ', loadCases(l)%t + print'(a,i0)', ' N: ', loadCases(l)%N + print'(a,i0)', ' f_out: ', loadCases(l)%f_out if (loadCases(l)%f_restart < huge(0)) & print'(a,i0)', ' f_restart: ', loadCases(l)%f_restart if (errorID > 0) call IO_error(error_ID = errorID, ext_msg = loadcase_string) ! exit with error message + endif reportAndCheck enddo @@ -309,8 +317,6 @@ program DAMASK_grid writeHeader: if (interface_restartInc < 1) then open(newunit=statUnit,file=trim(getSolverJobName())//'.sta',form='FORMATTED',status='REPLACE') write(statUnit,'(a)') 'Increment Time CutbackLevel Converged IterationsNeeded' ! statistics file - if (debug_grid%contains('basic')) print'(/,a)', ' header of statistics file written out' - flush(IO_STDOUT) else writeHeader open(newunit=statUnit,file=trim(getSolverJobName())//& '.sta',form='FORMATTED', position='APPEND', status='OLD') @@ -319,6 +325,7 @@ program DAMASK_grid writeUndeformed: if (interface_restartInc < 1) then print'(/,a)', ' ... writing initial configuration to file ........................' + flush(IO_STDOUT) call CPFEM_results(0,0.0_pReal) endif writeUndeformed diff --git a/src/grid/discretization_grid.f90 b/src/grid/discretization_grid.f90 index e869c0781..48ad5b7e1 100644 --- a/src/grid/discretization_grid.f90 +++ b/src/grid/discretization_grid.f90 @@ -19,7 +19,6 @@ module discretization_grid use results use discretization use geometry_plastic_nonlocal - use FEsolving implicit none private @@ -79,7 +78,7 @@ subroutine discretization_grid_init(restart) call MPI_Bcast(origin,3,MPI_DOUBLE,0,PETSC_COMM_WORLD, ierr) if (ierr /= 0) error stop 'MPI error' - print'(/,a,3(i12 ))', ' grid a b c: ', grid + print'(/,a,3(i12 ))', ' cells a b c: ', grid print'(a,3(es12.5))', ' size x y z: ', geomSize print'(a,3(es12.5))', ' origin x y z: ', origin @@ -117,17 +116,14 @@ subroutine discretization_grid_init(restart) (grid(1)+1) * (grid(2)+1) * grid3,& ! ...unless not last process worldrank+1==worldsize)) - FEsolving_execElem = [1,product(myGrid)] ! parallel loop bounds set to comprise all elements - FEsolving_execIP = [1,1] ! parallel loop bounds set to comprise the only IP - !-------------------------------------------------------------------------------------------------- ! store geometry information for post processing if(.not. restart) then call results_openJobFile call results_closeGroup(results_addGroup('geometry')) - call results_addAttribute('grid', grid, 'geometry') - call results_addAttribute('size', geomSize,'geometry') - call results_addAttribute('origin',origin, 'geometry') + call results_addAttribute('cells', grid, '/geometry') + call results_addAttribute('size', geomSize,'/geometry') + call results_addAttribute('origin',origin, '/geometry') call results_closeJobFile endif @@ -149,168 +145,6 @@ subroutine discretization_grid_init(restart) end subroutine discretization_grid_init -!-------------------------------------------------------------------------------------------------- -!> @brief Parses geometry file -!> @details important variables have an implicit "save" attribute. Therefore, this function is -! supposed to be called only once! -!-------------------------------------------------------------------------------------------------- -subroutine readGeom(grid,geomSize,origin,material) - - integer, dimension(3), intent(out) :: & - grid ! grid (across all processes!) - real(pReal), dimension(3), intent(out) :: & - geomSize, & ! size (across all processes!) - origin ! origin (across all processes!) - integer, dimension(:), intent(out), allocatable :: & - material - - character(len=:), allocatable :: rawData - character(len=65536) :: line - integer, allocatable, dimension(:) :: chunkPos - integer :: & - headerLength = -1, & !< length of header (in lines) - fileLength, & !< length of the geom file (in characters) - fileUnit, & - startPos, endPos, & - myStat, & - l, & !< line counter - c, & !< counter for # materials in line - o, & !< order of "to" packing - e, & !< "element", i.e. spectral collocation point - i, j - - grid = -1 - geomSize = -1.0_pReal - -!-------------------------------------------------------------------------------------------------- -! read raw data as stream - inquire(file = trim(interface_geomFile), size=fileLength) - open(newunit=fileUnit, file=trim(interface_geomFile), access='stream',& - status='old', position='rewind', action='read',iostat=myStat) - if(myStat /= 0) call IO_error(100,ext_msg=trim(interface_geomFile)) - allocate(character(len=fileLength)::rawData) - read(fileUnit) rawData - close(fileUnit) - -!-------------------------------------------------------------------------------------------------- -! get header length - endPos = index(rawData,IO_EOL) - if(endPos <= index(rawData,'head')) then ! ToDo: Should be 'header' - startPos = len(rawData) - call IO_error(error_ID=841, ext_msg='readGeom') - else - chunkPos = IO_stringPos(rawData(1:endPos)) - if (chunkPos(1) < 2) call IO_error(error_ID=841, ext_msg='readGeom') - headerLength = IO_intValue(rawData(1:endPos),chunkPos,1) - startPos = endPos + 1 - endif - -!-------------------------------------------------------------------------------------------------- -! read and interpret header - origin = 0.0_pReal - l = 0 - do while (l < headerLength .and. startPos < len(rawData)) - endPos = startPos + index(rawData(startPos:),IO_EOL) - 1 - if (endPos < startPos) endPos = len(rawData) ! end of file without new line - line = rawData(startPos:endPos) - startPos = endPos + 1 - l = l + 1 - - chunkPos = IO_stringPos(trim(line)) - if (chunkPos(1) < 2) cycle ! need at least one keyword value pair - - select case (IO_lc(IO_StringValue(trim(line),chunkPos,1)) ) - case ('grid') - if (chunkPos(1) > 6) then - do j = 2,6,2 - select case (IO_lc(IO_stringValue(line,chunkPos,j))) - case('a') - grid(1) = IO_intValue(line,chunkPos,j+1) - case('b') - grid(2) = IO_intValue(line,chunkPos,j+1) - case('c') - grid(3) = IO_intValue(line,chunkPos,j+1) - end select - enddo - endif - - case ('size') - if (chunkPos(1) > 6) then - do j = 2,6,2 - select case (IO_lc(IO_stringValue(line,chunkPos,j))) - case('x') - geomSize(1) = IO_floatValue(line,chunkPos,j+1) - case('y') - geomSize(2) = IO_floatValue(line,chunkPos,j+1) - case('z') - geomSize(3) = IO_floatValue(line,chunkPos,j+1) - end select - enddo - endif - - case ('origin') - if (chunkPos(1) > 6) then - do j = 2,6,2 - select case (IO_lc(IO_stringValue(line,chunkPos,j))) - case('x') - origin(1) = IO_floatValue(line,chunkPos,j+1) - case('y') - origin(2) = IO_floatValue(line,chunkPos,j+1) - case('z') - origin(3) = IO_floatValue(line,chunkPos,j+1) - end select - enddo - endif - - end select - - enddo - -!-------------------------------------------------------------------------------------------------- -! sanity checks - if(any(grid < 1)) & - call IO_error(error_ID = 842, ext_msg='grid (readGeom)') - if(any(geomSize < 0.0_pReal)) & - call IO_error(error_ID = 842, ext_msg='size (readGeom)') - - allocate(material(product(grid)), source = -1) ! too large in case of MPI (shrink later, not very elegant) - -!-------------------------------------------------------------------------------------------------- -! read and interpret content - e = 1 - do while (startPos < len(rawData)) - endPos = startPos + index(rawData(startPos:),IO_EOL) - 1 - if (endPos < startPos) endPos = len(rawData) ! end of file without new line - line = rawData(startPos:endPos) - startPos = endPos + 1 - l = l + 1 - chunkPos = IO_stringPos(trim(line)) - - noCompression: if (chunkPos(1) /= 3) then - c = chunkPos(1) - material(e:e+c-1) = [(IO_intValue(line,chunkPos,i+1), i=0, c-1)] - else noCompression - compression: if (IO_lc(IO_stringValue(line,chunkPos,2)) == 'of') then - c = IO_intValue(line,chunkPos,1) - material(e:e+c-1) = [(IO_intValue(line,chunkPos,3),i = 1,IO_intValue(line,chunkPos,1))] - else if (IO_lc(IO_stringValue(line,chunkPos,2)) == 'to') then compression - c = abs(IO_intValue(line,chunkPos,3) - IO_intValue(line,chunkPos,1)) + 1 - o = merge(+1, -1, IO_intValue(line,chunkPos,3) > IO_intValue(line,chunkPos,1)) - material(e:e+c-1) = [(i, i = IO_intValue(line,chunkPos,1),IO_intValue(line,chunkPos,3),o)] - else compression - c = chunkPos(1) - material(e:e+c-1) = [(IO_intValue(line,chunkPos,i+1), i=0, c-1)] - endif compression - endif noCompression - - e = e+c - end do - - if (e-1 /= product(grid)) call IO_error(error_ID = 843, el=e) - -end subroutine readGeom - - !-------------------------------------------------------------------------------------------------- !> @brief Parse vtk rectilinear grid (.vtr) !> @details https://vtk.org/Wiki/VTK_XML_Formats @@ -566,12 +400,12 @@ subroutine readVTR(grid,geomSize,origin,material) size_deflated = temp(4:) bytes_inflated = base64_to_bytes(base64_str(base64_nChar(headerLen)+1_pI64:)) - allocate(bytes(0)) + allocate(bytes(sum(size_inflated))) e = 0_pI64 do b = 1, nBlock s = e + 1_pI64 e = s + size_deflated(b) - 1_pI64 - bytes = [bytes,zlib_inflate(bytes_inflated(s:e),size_inflated(b))] + bytes(sum(size_inflated(:b-1))+1_pI64:sum(size_inflated(:b))) = zlib_inflate(bytes_inflated(s:e),size_inflated(b)) enddo end function asBytes_compressed diff --git a/src/grid/grid_damage_spectral.f90 b/src/grid/grid_damage_spectral.f90 index 4c014f3c0..79437945b 100644 --- a/src/grid/grid_damage_spectral.f90 +++ b/src/grid/grid_damage_spectral.f90 @@ -203,8 +203,7 @@ function grid_damage_spectral_solution(timeinc) result(solution) call VecMax(solution_vec,devNull,phi_max,ierr); CHKERRQ(ierr) if (solution%converged) & print'(/,a)', ' ... nonlocal damage converged .....................................' - write(IO_STDOUT,'(/,a,f8.6,2x,f8.6,2x,e11.4,/)',advance='no') ' Minimum|Maximum|Delta Damage = ',& - phi_min, phi_max, stagNorm + print'(/,a,f8.6,2x,f8.6,2x,e11.4)', ' Minimum|Maximum|Delta Damage = ', phi_min, phi_max, stagNorm print'(/,a)', ' ===========================================================================' flush(IO_STDOUT) diff --git a/src/grid/grid_mech_FEM.f90 b/src/grid/grid_mech_FEM.f90 index 7d0830f67..003f568c6 100644 --- a/src/grid/grid_mech_FEM.f90 +++ b/src/grid/grid_mech_FEM.f90 @@ -16,8 +16,8 @@ module grid_mech_FEM use IO use HDF5_utilities use math + use rotations use spectral_utilities - use FEsolving use config use homogenization use discretization @@ -30,16 +30,16 @@ module grid_mech_FEM type :: tNumerics integer :: & - itmin, & !< minimum number of iterations - itmax !< maximum number of iterations + itmin, & !< minimum number of iterations + itmax !< maximum number of iterations real(pReal) :: & - eps_div_atol, & !< absolute tolerance for equilibrium - eps_div_rtol, & !< relative tolerance for equilibrium - eps_stress_atol, & !< absolute tolerance for fullfillment of stress BC - eps_stress_rtol !< relative tolerance for fullfillment of stress BC + eps_div_atol, & !< absolute tolerance for equilibrium + eps_div_rtol, & !< relative tolerance for equilibrium + eps_stress_atol, & !< absolute tolerance for fullfillment of stress BC + eps_stress_rtol !< relative tolerance for fullfillment of stress BC end type tNumerics - type(tNumerics) :: num ! numerics parameters. Better name? + type(tNumerics) :: num ! numerics parameters. Better name? logical :: debugRotation @@ -63,7 +63,7 @@ module grid_mech_FEM real(pReal), dimension(3,3) :: & F_aimDot = 0.0_pReal, & !< assumed rate of average deformation gradient F_aim = math_I3, & !< current prescribed deformation gradient - F_aim_lastInc = math_I3, & !< previous average deformation gradient + F_aim_lastInc = math_I3, & !< previous average deformation gradient P_av = 0.0_pReal, & !< average 1st Piola--Kirchhoff stress P_aim = 0.0_pReal character(len=:), allocatable :: incInfo !< time and increment information @@ -92,10 +92,8 @@ contains !-------------------------------------------------------------------------------------------------- subroutine grid_mech_FEM_init - real(pReal) :: HGCoeff = 0.0e-2_pReal - real(pReal), dimension(3,3) :: & - temp33_Real = 0.0_pReal - real(pReal), dimension(4,8) :: & + real(pReal), parameter :: HGCoeff = 0.0e-2_pReal + real(pReal), parameter, dimension(4,8) :: & HGcomp = reshape([ 1.0_pReal, 1.0_pReal, 1.0_pReal,-1.0_pReal, & 1.0_pReal,-1.0_pReal,-1.0_pReal, 1.0_pReal, & -1.0_pReal, 1.0_pReal,-1.0_pReal, 1.0_pReal, & @@ -120,18 +118,19 @@ subroutine grid_mech_FEM_init !------------------------------------------------------------------------------------------------- ! debugging options - debug_grid => config_debug%get('grid', defaultVal=emptyList) + debug_grid => config_debug%get('grid',defaultVal=emptyList) debugRotation = debug_grid%contains('rotation') !------------------------------------------------------------------------------------------------- ! read numerical parameters and do sanity checks num_grid => config_numerics%get('grid',defaultVal=emptyDict) + num%eps_div_atol = num_grid%get_asFloat('eps_div_atol', defaultVal=1.0e-4_pReal) num%eps_div_rtol = num_grid%get_asFloat('eps_div_rtol', defaultVal=5.0e-4_pReal) num%eps_stress_atol = num_grid%get_asFloat('eps_stress_atol',defaultVal=1.0e3_pReal) num%eps_stress_rtol = num_grid%get_asFloat('eps_stress_rtol',defaultVal=1.0e-3_pReal) - num%itmin = num_grid%get_asInt ('itmin', defaultVal=1) - num%itmax = num_grid%get_asInt ('itmax', defaultVal=250) + num%itmin = num_grid%get_asInt ('itmin',defaultVal=1) + num%itmax = num_grid%get_asInt ('itmax',defaultVal=250) if (num%eps_div_atol <= 0.0_pReal) call IO_error(301,ext_msg='eps_div_atol') if (num%eps_div_rtol < 0.0_pReal) call IO_error(301,ext_msg='eps_div_rtol') @@ -224,6 +223,7 @@ subroutine grid_mech_FEM_init fileHandle = HDF5_openFile(fileName) groupHandle = HDF5_openGroup(fileHandle,'solver') + call HDF5_read(groupHandle,P_aim, 'P_aim') call HDF5_read(groupHandle,F_aim, 'F_aim') call HDF5_read(groupHandle,F_aim_lastInc,'F_aim_lastInc') call HDF5_read(groupHandle,F_aimDot, 'F_aimDot') @@ -237,9 +237,9 @@ subroutine grid_mech_FEM_init F = spread(spread(spread(math_I3,3,grid(1)),4,grid(2)),5,grid3) endif restartRead - homogenization_F0 = reshape(F_lastInc, [3,3,1,product(grid(1:2))*grid3]) ! set starting condition for materialpoint_stressAndItsTangent + homogenization_F0 = reshape(F_lastInc, [3,3,product(grid(1:2))*grid3]) ! set starting condition for materialpoint_stressAndItsTangent call utilities_updateCoords(F) - call utilities_constitutiveResponse(P_current,temp33_Real,C_volAvg,devNull, & ! stress field, stress avg, global average of stiffness and (min+max)/2 + call utilities_constitutiveResponse(P_current,P_av,C_volAvg,devNull, & ! stress field, stress avg, global average of stiffness and (min+max)/2 F, & ! target F 0.0_pReal) ! time increment call DMDAVecRestoreArrayF90(mech_grid,solution_current,u_current,ierr) @@ -294,6 +294,7 @@ function grid_mech_FEM_solution(incInfoIn) result(solution) solution%iterationsNeeded = totalIter solution%termIll = terminallyIll terminallyIll = .false. + P_aim = merge(P_aim,P_av,params%stress_mask) end function grid_mech_FEM_solution @@ -301,34 +302,26 @@ end function grid_mech_FEM_solution !-------------------------------------------------------------------------------------------------- !> @brief forwarding routine !> @details find new boundary conditions and best F estimate for end of current timestep -!> possibly writing restart information, triggering of state increment in DAMASK, and updating of IPcoordinates !-------------------------------------------------------------------------------------------------- -subroutine grid_mech_FEM_forward(cutBack,guess,timeinc,timeinc_old,loadCaseTime,& +subroutine grid_mech_FEM_forward(cutBack,guess,Delta_t,Delta_t_old,t_remaining,& deformation_BC,stress_BC,rotation_BC) - logical, intent(in) :: & + logical, intent(in) :: & cutBack, & guess - real(pReal), intent(in) :: & - timeinc_old, & - timeinc, & - loadCaseTime !< remaining time of current load case - type(tBoundaryCondition), intent(in) :: & + real(pReal), intent(in) :: & + Delta_t_old, & + Delta_t, & + t_remaining !< remaining time of current load case + type(tBoundaryCondition), intent(in) :: & stress_BC, & deformation_BC - type(rotation), intent(in) :: & + type(rotation), intent(in) :: & rotation_BC PetscErrorCode :: ierr PetscScalar, pointer, dimension(:,:,:,:) :: & u_current,u_lastInc -!-------------------------------------------------------------------------------------------------- -! set module wide available data - params%stress_mask = stress_BC%mask - params%rotation_BC = rotation_BC - params%timeinc = timeinc - params%timeincOld = timeinc_old - call DMDAVecGetArrayF90(mech_grid,solution_current,u_current,ierr); CHKERRQ(ierr) call DMDAVecGetArrayF90(mech_grid,solution_lastInc,u_lastInc,ierr); CHKERRQ(ierr) @@ -338,7 +331,7 @@ subroutine grid_mech_FEM_forward(cutBack,guess,timeinc,timeinc_old,loadCaseTime, else C_volAvgLastInc = C_volAvg - F_aimDot = merge(merge((F_aim-F_aim_lastInc)/timeinc_old,0.0_pReal,stress_BC%mask), 0.0_pReal, guess) + F_aimDot = merge(merge((F_aim-F_aim_lastInc)/Delta_t_old,0.0_pReal,stress_BC%mask), 0.0_pReal, guess) ! estimate deformation rate for prescribed stress components F_aim_lastInc = F_aim !----------------------------------------------------------------------------------------------- @@ -346,18 +339,18 @@ subroutine grid_mech_FEM_forward(cutBack,guess,timeinc,timeinc_old,loadCaseTime, if (deformation_BC%myType=='L') then ! calculate F_aimDot from given L and current F F_aimDot = F_aimDot & + merge(matmul(deformation_BC%values, F_aim_lastInc),.0_pReal,deformation_BC%mask) - elseif(deformation_BC%myType=='dot_F') then ! F_aimDot is prescribed - F_aimDot = F_aimDot & + elseif (deformation_BC%myType=='dot_F') then ! F_aimDot is prescribed + F_aimDot = F_aimDot & + merge(deformation_BC%values,.0_pReal,deformation_BC%mask) elseif (deformation_BC%myType=='F') then ! aim at end of load case is prescribed F_aimDot = F_aimDot & - + merge((deformation_BC%values - F_aim_lastInc)/loadCaseTime,.0_pReal,deformation_BC%mask) + + merge((deformation_BC%values - F_aim_lastInc)/t_remaining,.0_pReal,deformation_BC%mask) endif if (guess) then call VecWAXPY(solution_rate,-1.0_pReal,solution_lastInc,solution_current,ierr) CHKERRQ(ierr) - call VecScale(solution_rate,1.0_pReal/timeinc_old,ierr); CHKERRQ(ierr) + call VecScale(solution_rate,1.0_pReal/Delta_t_old,ierr); CHKERRQ(ierr) else call VecSet(solution_rate,0.0_pReal,ierr); CHKERRQ(ierr) endif @@ -365,28 +358,33 @@ subroutine grid_mech_FEM_forward(cutBack,guess,timeinc,timeinc_old,loadCaseTime, F_lastInc = F - homogenization_F0 = reshape(F, [3,3,1,product(grid(1:2))*grid3]) + homogenization_F0 = reshape(F, [3,3,product(grid(1:2))*grid3]) endif !-------------------------------------------------------------------------------------------------- ! update average and local deformation gradients - F_aim = F_aim_lastInc + F_aimDot * timeinc - if (stress_BC%myType=='P') then - P_aim = P_aim + merge((stress_BC%values - P_aim)/loadCaseTime*timeinc,.0_pReal,stress_BC%mask) - elseif (stress_BC%myType=='dot_P') then !UNTESTED - P_aim = P_aim + merge(stress_BC%values*timeinc,.0_pReal,stress_BC%mask) - endif + F_aim = F_aim_lastInc + F_aimDot * Delta_t + if (stress_BC%myType=='P') P_aim = P_aim & + + merge((stress_BC%values - P_aim)/t_remaining,0.0_pReal,stress_BC%mask)*Delta_t + if (stress_BC%myType=='dot_P') P_aim = P_aim & + + merge(stress_BC%values,0.0_pReal,stress_BC%mask)*Delta_t - call VecAXPY(solution_current,timeinc,solution_rate,ierr); CHKERRQ(ierr) + call VecAXPY(solution_current,Delta_t,solution_rate,ierr); CHKERRQ(ierr) - call DMDAVecRestoreArrayF90(mech_grid,solution_current,u_current,ierr);CHKERRQ(ierr) - call DMDAVecRestoreArrayF90(mech_grid,solution_lastInc,u_lastInc,ierr);CHKERRQ(ierr) + call DMDAVecRestoreArrayF90(mech_grid,solution_current,u_current,ierr); CHKERRQ(ierr) + call DMDAVecRestoreArrayF90(mech_grid,solution_lastInc,u_lastInc,ierr); CHKERRQ(ierr) + +!-------------------------------------------------------------------------------------------------- +! set module wide available data + params%stress_mask = stress_BC%mask + params%rotation_BC = rotation_BC + params%timeinc = Delta_t end subroutine grid_mech_FEM_forward !-------------------------------------------------------------------------------------------------- -!> @brief Age +!> @brief Update coordinates !-------------------------------------------------------------------------------------------------- subroutine grid_mech_FEM_updateCoords @@ -414,6 +412,7 @@ subroutine grid_mech_FEM_restartWrite fileHandle = HDF5_openFile(fileName,'w') groupHandle = HDF5_addGroup(fileHandle,'solver') + call HDF5_write(groupHandle,P_aim, 'P_aim') call HDF5_write(groupHandle,F_aim, 'F_aim') call HDF5_write(groupHandle,F_aim_lastInc,'F_aim_lastInc') call HDF5_write(groupHandle,F_aimDot, 'F_aimDot') @@ -440,11 +439,11 @@ end subroutine grid_mech_FEM_restartWrite subroutine converged(snes_local,PETScIter,devNull1,devNull2,fnorm,reason,dummy,ierr) SNES :: snes_local - PetscInt, intent(in) :: PETScIter - PetscReal, intent(in) :: & - devNull1, & - devNull2, & - fnorm + PetscInt, intent(in) :: PETScIter + PetscReal, intent(in) :: & + devNull1, & + devNull2, & + fnorm SNESConvergedReason :: reason PetscObject :: dummy PetscErrorCode :: ierr @@ -457,10 +456,10 @@ subroutine converged(snes_local,PETScIter,devNull1,devNull2,fnorm,reason,dummy,i divTol = max(maxval(abs(P_av))*num%eps_div_rtol ,num%eps_div_atol) BCTol = max(maxval(abs(P_av))*num%eps_stress_rtol,num%eps_stress_atol) - if ((totalIter >= num%itmin .and. & - all([ err_div/divTol, & - err_BC /BCTol ] < 1.0_pReal)) & - .or. terminallyIll) then + if (terminallyIll .or. & + (totalIter >= num%itmin .and. & + all([ err_div/divTol, & + err_BC /BCTol ] < 1.0_pReal))) then reason = 1 elseif (totalIter >= num%itmax) then reason = -1 @@ -509,11 +508,10 @@ subroutine formResidual(da_local,x_local, & newIteration: if (totalIter <= PETScIter) then totalIter = totalIter + 1 print'(1x,a,3(a,i0))', trim(incInfo), ' @ Iteration ', num%itmin, '≤',totalIter+1, '≤', num%itmax - if (debugRotation) & - write(IO_STDOUT,'(/,a,/,3(3(f12.7,1x)/))',advance='no') & - ' deformation gradient aim (lab) =', transpose(params%rotation_BC%rotate(F_aim,active=.true.)) - write(IO_STDOUT,'(/,a,/,3(3(f12.7,1x)/))',advance='no') & - ' deformation gradient aim =', transpose(F_aim) + if (debugRotation) print'(/,a,/,2(3(f12.7,1x)/),3(f12.7,1x))', & + ' deformation gradient aim (lab) =', transpose(params%rotation_BC%rotate(F_aim,active=.true.)) + print'(/,a,/,2(3(f12.7,1x)/),3(f12.7,1x))', & + ' deformation gradient aim =', transpose(F_aim) flush(IO_STDOUT) endif newIteration @@ -558,9 +556,9 @@ subroutine formResidual(da_local,x_local, & ii = i-xstart+1; jj = j-ystart+1; kk = k-zstart+1 ele = ele + 1 f_elem = matmul(transpose(BMat),transpose(P_current(1:3,1:3,ii,jj,kk)))*detJ + & - matmul(HGMat,x_elem)*(homogenization_dPdF(1,1,1,1,1,ele) + & - homogenization_dPdF(2,2,2,2,1,ele) + & - homogenization_dPdF(3,3,3,3,1,ele))/3.0_pReal + matmul(HGMat,x_elem)*(homogenization_dPdF(1,1,1,1,ele) + & + homogenization_dPdF(2,2,2,2,ele) + & + homogenization_dPdF(3,3,3,3,ele))/3.0_pReal ctr = 0 do kk = 0, 1; do jj = 0, 1; do ii = 0, 1 ctr = ctr + 1 @@ -637,18 +635,18 @@ subroutine formJacobian(da_local,x_local,Jac_pre,Jac,dummy,ierr) row = col ele = ele + 1 K_ele = 0.0 - K_ele(1 :8 ,1 :8 ) = HGMat*(homogenization_dPdF(1,1,1,1,1,ele) + & - homogenization_dPdF(2,2,2,2,1,ele) + & - homogenization_dPdF(3,3,3,3,1,ele))/3.0_pReal - K_ele(9 :16,9 :16) = HGMat*(homogenization_dPdF(1,1,1,1,1,ele) + & - homogenization_dPdF(2,2,2,2,1,ele) + & - homogenization_dPdF(3,3,3,3,1,ele))/3.0_pReal - K_ele(17:24,17:24) = HGMat*(homogenization_dPdF(1,1,1,1,1,ele) + & - homogenization_dPdF(2,2,2,2,1,ele) + & - homogenization_dPdF(3,3,3,3,1,ele))/3.0_pReal + K_ele(1 :8 ,1 :8 ) = HGMat*(homogenization_dPdF(1,1,1,1,ele) + & + homogenization_dPdF(2,2,2,2,ele) + & + homogenization_dPdF(3,3,3,3,ele))/3.0_pReal + K_ele(9 :16,9 :16) = HGMat*(homogenization_dPdF(1,1,1,1,ele) + & + homogenization_dPdF(2,2,2,2,ele) + & + homogenization_dPdF(3,3,3,3,ele))/3.0_pReal + K_ele(17:24,17:24) = HGMat*(homogenization_dPdF(1,1,1,1,ele) + & + homogenization_dPdF(2,2,2,2,ele) + & + homogenization_dPdF(3,3,3,3,ele))/3.0_pReal K_ele = K_ele + & matmul(transpose(BMatFull), & - matmul(reshape(reshape(homogenization_dPdF(1:3,1:3,1:3,1:3,1,ele), & + matmul(reshape(reshape(homogenization_dPdF(1:3,1:3,1:3,1:3,ele), & shape=[3,3,3,3], order=[2,1,4,3]),shape=[9,9]),BMatFull))*detJ call MatSetValuesStencil(Jac,24,row,24,col,K_ele,ADD_VALUES,ierr) CHKERRQ(ierr) @@ -665,16 +663,16 @@ subroutine formJacobian(da_local,x_local,Jac_pre,Jac,dummy,ierr) C_volAvg(3,3,3,3)/delta(3)**2.0_pReal)*detJ call MatZeroRowsColumns(Jac,size(rows),rows,diag,PETSC_NULL_VEC,PETSC_NULL_VEC,ierr) CHKERRQ(ierr) - call DMGetGlobalVector(da_local,coordinates,ierr);CHKERRQ(ierr) - call DMDAVecGetArrayF90(da_local,coordinates,x_scal,ierr);CHKERRQ(ierr) + call DMGetGlobalVector(da_local,coordinates,ierr); CHKERRQ(ierr) + call DMDAVecGetArrayF90(da_local,coordinates,x_scal,ierr); CHKERRQ(ierr) ele = 0 do k = zstart, zend; do j = ystart, yend; do i = xstart, xend ele = ele + 1 x_scal(0:2,i,j,k) = discretization_IPcoords(1:3,ele) enddo; enddo; enddo - call DMDAVecRestoreArrayF90(da_local,coordinates,x_scal,ierr);CHKERRQ(ierr) ! initialize to undeformed coordinates (ToDo: use ip coordinates) - call MatNullSpaceCreateRigidBody(coordinates,matnull,ierr);CHKERRQ(ierr) ! get rigid body deformation modes - call DMRestoreGlobalVector(da_local,coordinates,ierr);CHKERRQ(ierr) + call DMDAVecRestoreArrayF90(da_local,coordinates,x_scal,ierr); CHKERRQ(ierr) ! initialize to undeformed coordinates (ToDo: use ip coordinates) + call MatNullSpaceCreateRigidBody(coordinates,matnull,ierr); CHKERRQ(ierr) ! get rigid body deformation modes + call DMRestoreGlobalVector(da_local,coordinates,ierr); CHKERRQ(ierr) call MatSetNullSpace(Jac,matnull,ierr); CHKERRQ(ierr) call MatSetNearNullSpace(Jac,matnull,ierr); CHKERRQ(ierr) call MatNullSpaceDestroy(matnull,ierr); CHKERRQ(ierr) diff --git a/src/grid/grid_mech_spectral_basic.f90 b/src/grid/grid_mech_spectral_basic.f90 index 8677a998f..9bc36165f 100644 --- a/src/grid/grid_mech_spectral_basic.f90 +++ b/src/grid/grid_mech_spectral_basic.f90 @@ -16,8 +16,8 @@ module grid_mech_spectral_basic use IO use HDF5_utilities use math + use rotations use spectral_utilities - use FEsolving use config use homogenization use discretization_grid @@ -93,8 +93,6 @@ contains subroutine grid_mech_spectral_basic_init real(pReal), dimension(3,3,grid(1),grid(2),grid3) :: P - real(pReal), dimension(3,3) :: & - temp33_Real = 0.0_pReal PetscErrorCode :: ierr PetscScalar, pointer, dimension(:,:,:,:) :: & F ! pointer to solution data @@ -117,20 +115,20 @@ subroutine grid_mech_spectral_basic_init !------------------------------------------------------------------------------------------------- ! debugging options - debug_grid => config_debug%get('grid', defaultVal=emptyList) + debug_grid => config_debug%get('grid',defaultVal=emptyList) debugRotation = debug_grid%contains('rotation') - + !------------------------------------------------------------------------------------------------- ! read numerical parameters and do sanity checks num_grid => config_numerics%get('grid',defaultVal=emptyDict) - num%update_gamma = num_grid%get_asBool ('update_gamma', defaultVal=.false.) - num%eps_div_atol = num_grid%get_asFloat ('eps_div_atol', defaultVal=1.0e-4_pReal) - num%eps_div_rtol = num_grid%get_asFloat ('eps_div_rtol', defaultVal=5.0e-4_pReal) - num%eps_stress_atol = num_grid%get_asFloat ('eps_stress_atol',defaultVal=1.0e3_pReal) - num%eps_stress_rtol = num_grid%get_asFloat ('eps_stress_rtol',defaultVal=1.0e-3_pReal) - num%itmin = num_grid%get_asInt ('itmin',defaultVal=1) - num%itmax = num_grid%get_asInt ('itmax',defaultVal=250) + num%update_gamma = num_grid%get_asBool ('update_gamma', defaultVal=.false.) + num%eps_div_atol = num_grid%get_asFloat('eps_div_atol', defaultVal=1.0e-4_pReal) + num%eps_div_rtol = num_grid%get_asFloat('eps_div_rtol', defaultVal=5.0e-4_pReal) + num%eps_stress_atol = num_grid%get_asFloat('eps_stress_atol',defaultVal=1.0e3_pReal) + num%eps_stress_rtol = num_grid%get_asFloat('eps_stress_rtol',defaultVal=1.0e-3_pReal) + num%itmin = num_grid%get_asInt ('itmin',defaultVal=1) + num%itmax = num_grid%get_asInt ('itmax',defaultVal=250) if (num%eps_div_atol <= 0.0_pReal) call IO_error(301,ext_msg='eps_div_atol') if (num%eps_div_rtol < 0.0_pReal) call IO_error(301,ext_msg='eps_div_rtol') @@ -138,7 +136,7 @@ subroutine grid_mech_spectral_basic_init if (num%eps_stress_rtol < 0.0_pReal) call IO_error(301,ext_msg='eps_stress_rtol') if (num%itmax <= 1) call IO_error(301,ext_msg='itmax') if (num%itmin > num%itmax .or. num%itmin < 1) call IO_error(301,ext_msg='itmin') - + !-------------------------------------------------------------------------------------------------- ! set default and user defined options for PETSc call PetscOptionsInsertString(PETSC_NULL_OPTIONS,'-mech_snes_type ngmres',ierr) @@ -148,14 +146,14 @@ subroutine grid_mech_spectral_basic_init !-------------------------------------------------------------------------------------------------- ! allocate global fields - allocate (F_lastInc(3,3,grid(1),grid(2),grid3),source = 0.0_pReal) - allocate (Fdot (3,3,grid(1),grid(2),grid3),source = 0.0_pReal) + allocate(F_lastInc(3,3,grid(1),grid(2),grid3),source = 0.0_pReal) + allocate(Fdot (3,3,grid(1),grid(2),grid3),source = 0.0_pReal) !-------------------------------------------------------------------------------------------------- ! initialize solver specific parts of PETSc call SNESCreate(PETSC_COMM_WORLD,snes,ierr); CHKERRQ(ierr) call SNESSetOptionsPrefix(snes,'mech_',ierr);CHKERRQ(ierr) - localK = 0 + localK = 0 localK(worldrank) = grid3 call MPI_Allreduce(MPI_IN_PLACE,localK,worldsize,MPI_INTEGER,MPI_SUM,PETSC_COMM_WORLD,ierr) call DMDACreate3d(PETSC_COMM_WORLD, & @@ -188,6 +186,7 @@ subroutine grid_mech_spectral_basic_init fileHandle = HDF5_openFile(fileName) groupHandle = HDF5_openGroup(fileHandle,'solver') + call HDF5_read(groupHandle,P_aim, 'P_aim') call HDF5_read(groupHandle,F_aim, 'F_aim') call HDF5_read(groupHandle,F_aim_lastInc,'F_aim_lastInc') call HDF5_read(groupHandle,F_aimDot, 'F_aimDot') @@ -199,9 +198,9 @@ subroutine grid_mech_spectral_basic_init F = reshape(F_lastInc,[9,grid(1),grid(2),grid3]) endif restartRead - homogenization_F0 = reshape(F_lastInc, [3,3,1,product(grid(1:2))*grid3]) ! set starting condition for materialpoint_stressAndItsTangent + homogenization_F0 = reshape(F_lastInc, [3,3,product(grid(1:2))*grid3]) ! set starting condition for materialpoint_stressAndItsTangent call utilities_updateCoords(reshape(F,shape(F_lastInc))) - call utilities_constitutiveResponse(P,temp33_Real,C_volAvg,C_minMaxAvg, & ! stress field, stress avg, global average of stiffness and (min+max)/2 + call utilities_constitutiveResponse(P,P_av,C_volAvg,C_minMaxAvg, & ! stress field, stress avg, global average of stiffness and (min+max)/2 reshape(F,shape(F_lastInc)), & ! target F 0.0_pReal) ! time increment call DMDAVecRestoreArrayF90(da,solution_vec,F,ierr); CHKERRQ(ierr) ! deassociate pointer @@ -261,6 +260,7 @@ function grid_mech_spectral_basic_solution(incInfoIn) result(solution) solution%iterationsNeeded = totalIter solution%termIll = terminallyIll terminallyIll = .false. + P_aim = merge(P_aim,P_av,params%stress_mask) end function grid_mech_spectral_basic_solution @@ -268,32 +268,25 @@ end function grid_mech_spectral_basic_solution !-------------------------------------------------------------------------------------------------- !> @brief forwarding routine !> @details find new boundary conditions and best F estimate for end of current timestep -!> possibly writing restart information, triggering of state increment in DAMASK, and updating of IPcoordinates !-------------------------------------------------------------------------------------------------- -subroutine grid_mech_spectral_basic_forward(cutBack,guess,timeinc,timeinc_old,loadCaseTime,& +subroutine grid_mech_spectral_basic_forward(cutBack,guess,Delta_t,Delta_t_old,t_remaining,& deformation_BC,stress_BC,rotation_BC) - logical, intent(in) :: & + logical, intent(in) :: & cutBack, & guess - real(pReal), intent(in) :: & - timeinc_old, & - timeinc, & - loadCaseTime !< remaining time of current load case - type(tBoundaryCondition), intent(in) :: & + real(pReal), intent(in) :: & + Delta_t_old, & + Delta_t, & + t_remaining !< remaining time of current load case + type(tBoundaryCondition), intent(in) :: & stress_BC, & deformation_BC - type(rotation), intent(in) :: & + type(rotation), intent(in) :: & rotation_BC PetscErrorCode :: ierr PetscScalar, pointer, dimension(:,:,:,:) :: F -!-------------------------------------------------------------------------------------------------- -! set module wide available data - params%stress_mask = stress_BC%mask - params%rotation_BC = rotation_BC - params%timeinc = timeinc - params%timeincOld = timeinc_old call DMDAVecGetArrayF90(da,solution_vec,F,ierr); CHKERRQ(ierr) @@ -304,7 +297,7 @@ subroutine grid_mech_spectral_basic_forward(cutBack,guess,timeinc,timeinc_old,lo C_volAvgLastInc = C_volAvg C_minMaxAvgLastInc = C_minMaxAvg - F_aimDot = merge(merge((F_aim-F_aim_lastInc)/timeinc_old,0.0_pReal,stress_BC%mask), 0.0_pReal, guess) + F_aimDot = merge(merge((F_aim-F_aim_lastInc)/Delta_t_old,0.0_pReal,stress_BC%mask), 0.0_pReal, guess) ! estimate deformation rate for prescribed stress components F_aim_lastInc = F_aim !----------------------------------------------------------------------------------------------- @@ -312,40 +305,45 @@ subroutine grid_mech_spectral_basic_forward(cutBack,guess,timeinc,timeinc_old,lo if (deformation_BC%myType=='L') then ! calculate F_aimDot from given L and current F F_aimDot = F_aimDot & + merge(matmul(deformation_BC%values, F_aim_lastInc),.0_pReal,deformation_BC%mask) - elseif(deformation_BC%myType=='dot_F') then ! F_aimDot is prescribed - F_aimDot = F_aimDot & + elseif (deformation_BC%myType=='dot_F') then ! F_aimDot is prescribed + F_aimDot = F_aimDot & + merge(deformation_BC%values,.0_pReal,deformation_BC%mask) elseif (deformation_BC%myType=='F') then ! aim at end of load case is prescribed F_aimDot = F_aimDot & - + merge((deformation_BC%values - F_aim_lastInc)/loadCaseTime,.0_pReal,deformation_BC%mask) + + merge((deformation_BC%values - F_aim_lastInc)/t_remaining,.0_pReal,deformation_BC%mask) endif Fdot = utilities_calculateRate(guess, & - F_lastInc,reshape(F,[3,3,grid(1),grid(2),grid3]),timeinc_old, & + F_lastInc,reshape(F,[3,3,grid(1),grid(2),grid3]),Delta_t_old, & rotation_BC%rotate(F_aimDot,active=.true.)) F_lastInc = reshape(F,[3,3,grid(1),grid(2),grid3]) - homogenization_F0 = reshape(F, [3,3,1,product(grid(1:2))*grid3]) + homogenization_F0 = reshape(F,[3,3,product(grid(1:2))*grid3]) endif !-------------------------------------------------------------------------------------------------- ! update average and local deformation gradients - F_aim = F_aim_lastInc + F_aimDot * timeinc - if (stress_BC%myType=='P') then - P_aim = P_aim + merge((stress_BC%values - P_aim)/loadCaseTime*timeinc,.0_pReal,stress_BC%mask) - elseif (stress_BC%myType=='dot_P') then !UNTESTED - P_aim = P_aim + merge(stress_BC%values*timeinc,.0_pReal,stress_BC%mask) - endif - - F = reshape(utilities_forwardField(timeinc,F_lastInc,Fdot, & ! estimate of F at end of time+timeinc that matches rotated F_aim on average + F_aim = F_aim_lastInc + F_aimDot * Delta_t + if (stress_BC%myType=='P') P_aim = P_aim & + + merge((stress_BC%values - P_aim)/t_remaining,0.0_pReal,stress_BC%mask)*Delta_t + if (stress_BC%myType=='dot_P') P_aim = P_aim & + + merge(stress_BC%values,0.0_pReal,stress_BC%mask)*Delta_t + + F = reshape(utilities_forwardField(Delta_t,F_lastInc,Fdot, & ! estimate of F at end of time+Delta_t that matches rotated F_aim on average rotation_BC%rotate(F_aim,active=.true.)),[9,grid(1),grid(2),grid3]) call DMDAVecRestoreArrayF90(da,solution_vec,F,ierr); CHKERRQ(ierr) +!-------------------------------------------------------------------------------------------------- +! set module wide available data + params%stress_mask = stress_BC%mask + params%rotation_BC = rotation_BC + params%timeinc = Delta_t + end subroutine grid_mech_spectral_basic_forward !-------------------------------------------------------------------------------------------------- -!> @brief Age +!> @brief Update coordinates !-------------------------------------------------------------------------------------------------- subroutine grid_mech_spectral_basic_updateCoords @@ -377,6 +375,7 @@ subroutine grid_mech_spectral_basic_restartWrite fileHandle = HDF5_openFile(fileName,'w') groupHandle = HDF5_addGroup(fileHandle,'solver') + call HDF5_write(groupHandle,P_aim, 'P_aim') call HDF5_write(groupHandle,F_aim, 'F_aim') call HDF5_write(groupHandle,F_aim_lastInc,'F_aim_lastInc') call HDF5_write(groupHandle,F_aimDot, 'F_aimDot') @@ -462,7 +461,7 @@ subroutine formResidual(in, F, & PetscErrorCode :: ierr call SNESGetNumberFunctionEvals(snes,nfuncs,ierr); CHKERRQ(ierr) - call SNESGetIterationNumber(snes,PETScIter,ierr); CHKERRQ(ierr) + call SNESGetIterationNumber(snes,PETScIter,ierr); CHKERRQ(ierr) if (nfuncs == 0 .and. PETScIter == 0) totalIter = -1 ! new increment @@ -471,11 +470,10 @@ subroutine formResidual(in, F, & newIteration: if (totalIter <= PETScIter) then totalIter = totalIter + 1 print'(1x,a,3(a,i0))', trim(incInfo), ' @ Iteration ', num%itmin, '≤',totalIter, '≤', num%itmax - if (debugRotation) & - write(IO_STDOUT,'(/,a,/,3(3(f12.7,1x)/))',advance='no') & - ' deformation gradient aim (lab) =', transpose(params%rotation_BC%rotate(F_aim,active=.true.)) - write(IO_STDOUT,'(/,a,/,3(3(f12.7,1x)/))',advance='no') & - ' deformation gradient aim =', transpose(F_aim) + if (debugRotation) print'(/,a,/,2(3(f12.7,1x)/),3(f12.7,1x))', & + ' deformation gradient aim (lab) =', transpose(params%rotation_BC%rotate(F_aim,active=.true.)) + print'(/,a,/,2(3(f12.7,1x)/),3(f12.7,1x))', & + ' deformation gradient aim =', transpose(F_aim) flush(IO_STDOUT) endif newIteration diff --git a/src/grid/grid_mech_spectral_polarisation.f90 b/src/grid/grid_mech_spectral_polarisation.f90 index 053d958ad..7160c1adc 100644 --- a/src/grid/grid_mech_spectral_polarisation.f90 +++ b/src/grid/grid_mech_spectral_polarisation.f90 @@ -16,8 +16,8 @@ module grid_mech_spectral_polarisation use IO use HDF5_utilities use math + use rotations use spectral_utilities - use FEsolving use config use homogenization use discretization_grid @@ -104,8 +104,6 @@ contains subroutine grid_mech_spectral_polarisation_init real(pReal), dimension(3,3,grid(1),grid(2),grid3) :: P - real(pReal), dimension(3,3) :: & - temp33_Real = 0.0_pReal PetscErrorCode :: ierr PetscScalar, pointer, dimension(:,:,:,:) :: & FandF_tau, & ! overall pointer to solution data @@ -146,16 +144,16 @@ subroutine grid_mech_spectral_polarisation_init num%alpha = num_grid%get_asFloat('alpha', defaultVal=1.0_pReal) num%beta = num_grid%get_asFloat('beta', defaultVal=1.0_pReal) - if (num%eps_div_atol <= 0.0_pReal) call IO_error(301,ext_msg='eps_div_atol') - if (num%eps_div_rtol < 0.0_pReal) call IO_error(301,ext_msg='eps_div_rtol') - if (num%eps_curl_atol <= 0.0_pReal) call IO_error(301,ext_msg='eps_curl_atol') - if (num%eps_curl_rtol < 0.0_pReal) call IO_error(301,ext_msg='eps_curl_rtol') - if (num%eps_stress_atol <= 0.0_pReal) call IO_error(301,ext_msg='eps_stress_atol') - if (num%eps_stress_rtol < 0.0_pReal) call IO_error(301,ext_msg='eps_stress_rtol') - if (num%itmax <= 1) call IO_error(301,ext_msg='itmax') - if (num%itmin > num%itmax .or. num%itmin < 1) call IO_error(301,ext_msg='itmin') - if (num%alpha <= 0.0_pReal .or. num%alpha > 2.0_pReal) call IO_error(301,ext_msg='alpha') - if (num%beta < 0.0_pReal .or. num%beta > 2.0_pReal) call IO_error(301,ext_msg='beta') + if (num%eps_div_atol <= 0.0_pReal) call IO_error(301,ext_msg='eps_div_atol') + if (num%eps_div_rtol < 0.0_pReal) call IO_error(301,ext_msg='eps_div_rtol') + if (num%eps_curl_atol <= 0.0_pReal) call IO_error(301,ext_msg='eps_curl_atol') + if (num%eps_curl_rtol < 0.0_pReal) call IO_error(301,ext_msg='eps_curl_rtol') + if (num%eps_stress_atol <= 0.0_pReal) call IO_error(301,ext_msg='eps_stress_atol') + if (num%eps_stress_rtol < 0.0_pReal) call IO_error(301,ext_msg='eps_stress_rtol') + if (num%itmax <= 1) call IO_error(301,ext_msg='itmax') + if (num%itmin > num%itmax .or. num%itmin < 1) call IO_error(301,ext_msg='itmin') + if (num%alpha <= 0.0_pReal .or. num%alpha > 2.0_pReal) call IO_error(301,ext_msg='alpha') + if (num%beta < 0.0_pReal .or. num%beta > 2.0_pReal) call IO_error(301,ext_msg='beta') !-------------------------------------------------------------------------------------------------- ! set default and user defined options for PETSc @@ -210,6 +208,7 @@ subroutine grid_mech_spectral_polarisation_init fileHandle = HDF5_openFile(fileName) groupHandle = HDF5_openGroup(fileHandle,'solver') + call HDF5_read(groupHandle,P_aim, 'P_aim') call HDF5_read(groupHandle,F_aim, 'F_aim') call HDF5_read(groupHandle,F_aim_lastInc,'F_aim_lastInc') call HDF5_read(groupHandle,F_aimDot, 'F_aimDot') @@ -225,9 +224,9 @@ subroutine grid_mech_spectral_polarisation_init F_tau_lastInc = 2.0_pReal*F_lastInc endif restartRead - homogenization_F0 = reshape(F_lastInc, [3,3,1,product(grid(1:2))*grid3]) ! set starting condition for materialpoint_stressAndItsTangent + homogenization_F0 = reshape(F_lastInc, [3,3,product(grid(1:2))*grid3]) ! set starting condition for materialpoint_stressAndItsTangent call utilities_updateCoords(reshape(F,shape(F_lastInc))) - call utilities_constitutiveResponse(P,temp33_Real,C_volAvg,C_minMaxAvg, & ! stress field, stress avg, global average of stiffness and (min+max)/2 + call utilities_constitutiveResponse(P,P_av,C_volAvg,C_minMaxAvg, & ! stress field, stress avg, global average of stiffness and (min+max)/2 reshape(F,shape(F_lastInc)), & ! target F 0.0_pReal) ! time increment call DMDAVecRestoreArrayF90(da,solution_vec,FandF_tau,ierr); CHKERRQ(ierr) ! deassociate pointer @@ -293,6 +292,7 @@ function grid_mech_spectral_polarisation_solution(incInfoIn) result(solution) solution%iterationsNeeded = totalIter solution%termIll = terminallyIll terminallyIll = .false. + P_aim = merge(P_aim,P_av,params%stress_mask) end function grid_mech_spectral_polarisation_solution @@ -300,34 +300,27 @@ end function grid_mech_spectral_polarisation_solution !-------------------------------------------------------------------------------------------------- !> @brief forwarding routine !> @details find new boundary conditions and best F estimate for end of current timestep -!> possibly writing restart information, triggering of state increment in DAMASK, and updating of IPcoordinates !-------------------------------------------------------------------------------------------------- -subroutine grid_mech_spectral_polarisation_forward(cutBack,guess,timeinc,timeinc_old,loadCaseTime,& +subroutine grid_mech_spectral_polarisation_forward(cutBack,guess,Delta_t,Delta_t_old,t_remaining,& deformation_BC,stress_BC,rotation_BC) - logical, intent(in) :: & + logical, intent(in) :: & cutBack, & guess - real(pReal), intent(in) :: & - timeinc_old, & - timeinc, & - loadCaseTime !< remaining time of current load case - type(tBoundaryCondition), intent(in) :: & + real(pReal), intent(in) :: & + Delta_t_old, & + Delta_t, & + t_remaining !< remaining time of current load case + type(tBoundaryCondition), intent(in) :: & stress_BC, & deformation_BC - type(rotation), intent(in) :: & + type(rotation), intent(in) :: & rotation_BC PetscErrorCode :: ierr PetscScalar, pointer, dimension(:,:,:,:) :: FandF_tau, F, F_tau integer :: i, j, k real(pReal), dimension(3,3) :: F_lambda33 -!-------------------------------------------------------------------------------------------------- -! set module wide available data - params%stress_mask = stress_BC%mask - params%rotation_BC = rotation_BC - params%timeinc = timeinc - params%timeincOld = timeinc_old call DMDAVecGetArrayF90(da,solution_vec,FandF_tau,ierr); CHKERRQ(ierr) F => FandF_tau(0: 8,:,:,:) @@ -340,7 +333,7 @@ subroutine grid_mech_spectral_polarisation_forward(cutBack,guess,timeinc,timeinc C_volAvgLastInc = C_volAvg C_minMaxAvgLastInc = C_minMaxAvg - F_aimDot = merge(merge((F_aim-F_aim_lastInc)/timeinc_old,0.0_pReal,stress_BC%mask), 0.0_pReal, guess) + F_aimDot = merge(merge((F_aim-F_aim_lastInc)/Delta_t_old,0.0_pReal,stress_BC%mask), 0.0_pReal, guess) ! estimate deformation rate for prescribed stress components F_aim_lastInc = F_aim !----------------------------------------------------------------------------------------------- @@ -348,60 +341,63 @@ subroutine grid_mech_spectral_polarisation_forward(cutBack,guess,timeinc,timeinc if (deformation_BC%myType=='L') then ! calculate F_aimDot from given L and current F F_aimDot = F_aimDot & + merge(matmul(deformation_BC%values, F_aim_lastInc),.0_pReal,deformation_BC%mask) - elseif(deformation_BC%myType=='dot_F') then ! F_aimDot is prescribed - F_aimDot = F_aimDot & + elseif (deformation_BC%myType=='dot_F') then ! F_aimDot is prescribed + F_aimDot = F_aimDot & + merge(deformation_BC%values,.0_pReal,deformation_BC%mask) elseif (deformation_BC%myType=='F') then ! aim at end of load case is prescribed F_aimDot = F_aimDot & - + merge((deformation_BC%values - F_aim_lastInc)/loadCaseTime,.0_pReal,deformation_BC%mask) + + merge((deformation_BC%values - F_aim_lastInc)/t_remaining,.0_pReal,deformation_BC%mask) endif Fdot = utilities_calculateRate(guess, & - F_lastInc,reshape(F,[3,3,grid(1),grid(2),grid3]),timeinc_old, & + F_lastInc,reshape(F,[3,3,grid(1),grid(2),grid3]),Delta_t_old, & rotation_BC%rotate(F_aimDot,active=.true.)) F_tauDot = utilities_calculateRate(guess, & - F_tau_lastInc,reshape(F_tau,[3,3,grid(1),grid(2),grid3]), timeinc_old, & + F_tau_lastInc,reshape(F_tau,[3,3,grid(1),grid(2),grid3]), Delta_t_old, & rotation_BC%rotate(F_aimDot,active=.true.)) F_lastInc = reshape(F, [3,3,grid(1),grid(2),grid3]) F_tau_lastInc = reshape(F_tau,[3,3,grid(1),grid(2),grid3]) - homogenization_F0 = reshape(F,[3,3,1,product(grid(1:2))*grid3]) + homogenization_F0 = reshape(F,[3,3,product(grid(1:2))*grid3]) endif !-------------------------------------------------------------------------------------------------- ! update average and local deformation gradients - F_aim = F_aim_lastInc + F_aimDot * timeinc - if (stress_BC%myType=='P') then - P_aim = P_aim + merge((stress_BC%values - P_aim)/loadCaseTime*timeinc,.0_pReal,stress_BC%mask) - elseif (stress_BC%myType=='dot_P') then !UNTESTED - P_aim = P_aim + merge(stress_BC%values*timeinc,.0_pReal,stress_BC%mask) - endif + F_aim = F_aim_lastInc + F_aimDot * Delta_t + if(stress_BC%myType=='P') P_aim = P_aim & + + merge((stress_BC%values - P_aim)/t_remaining,0.0_pReal,stress_BC%mask)*Delta_t + if(stress_BC%myType=='dot_P') P_aim = P_aim & + + merge(stress_BC%values,0.0_pReal,stress_BC%mask)*Delta_t - F = reshape(utilities_forwardField(timeinc,F_lastInc,Fdot, & ! estimate of F at end of time+timeinc that matches rotated F_aim on average + F = reshape(utilities_forwardField(Delta_t,F_lastInc,Fdot, & ! estimate of F at end of time+Delta_t that matches rotated F_aim on average rotation_BC%rotate(F_aim,active=.true.)),& [9,grid(1),grid(2),grid3]) if (guess) then - F_tau = reshape(Utilities_forwardField(timeinc,F_tau_lastInc,F_taudot), & + F_tau = reshape(Utilities_forwardField(Delta_t,F_tau_lastInc,F_taudot), & [9,grid(1),grid(2),grid3]) ! does not have any average value as boundary condition else do k = 1, grid3; do j = 1, grid(2); do i = 1, grid(1) F_lambda33 = reshape(F_tau(1:9,i,j,k)-F(1:9,i,j,k),[3,3]) - F_lambda33 = math_mul3333xx33(S_scale,matmul(F_lambda33, & - math_mul3333xx33(C_scale,& - matmul(transpose(F_lambda33),& - F_lambda33)-math_I3))*0.5_pReal) & - + math_I3 + F_lambda33 = math_I3 & + + math_mul3333xx33(S_scale,0.5_pReal*matmul(F_lambda33, & + math_mul3333xx33(C_scale,matmul(transpose(F_lambda33),F_lambda33)-math_I3))) F_tau(1:9,i,j,k) = reshape(F_lambda33,[9])+F(1:9,i,j,k) enddo; enddo; enddo endif call DMDAVecRestoreArrayF90(da,solution_vec,FandF_tau,ierr); CHKERRQ(ierr) +!-------------------------------------------------------------------------------------------------- +! set module wide available data + params%stress_mask = stress_BC%mask + params%rotation_BC = rotation_BC + params%timeinc = Delta_t + end subroutine grid_mech_spectral_polarisation_forward !-------------------------------------------------------------------------------------------------- -!> @brief Age +!> @brief Update coordinates !-------------------------------------------------------------------------------------------------- subroutine grid_mech_spectral_polarisation_updateCoords @@ -435,6 +431,7 @@ subroutine grid_mech_spectral_polarisation_restartWrite fileHandle = HDF5_openFile(fileName,'w') groupHandle = HDF5_addGroup(fileHandle,'solver') + call HDF5_write(groupHandle,F_aim, 'P_aim') call HDF5_write(groupHandle,F_aim, 'F_aim') call HDF5_write(groupHandle,F_aim_lastInc,'F_aim_lastInc') call HDF5_write(groupHandle,F_aimDot, 'F_aimDot') @@ -479,11 +476,11 @@ subroutine converged(snes_local,PETScIter,devNull1,devNull2,devNull3,reason,dumm divTol = max(maxval(abs(P_av)) *num%eps_div_rtol ,num%eps_div_atol) BCTol = max(maxval(abs(P_av)) *num%eps_stress_rtol,num%eps_stress_atol) - if ((totalIter >= num%itmin .and. & - all([ err_div /divTol, & - err_curl/curlTol, & - err_BC /BCTol ] < 1.0_pReal)) & - .or. terminallyIll) then + if (terminallyIll .or. & + (totalIter >= num%itmin .and. & + all([ err_div /divTol, & + err_curl/curlTol, & + err_BC /BCTol ] < 1.0_pReal))) then reason = 1 elseif (totalIter >= num%itmax) then reason = -1 @@ -554,11 +551,10 @@ subroutine formResidual(in, FandF_tau, & newIteration: if (totalIter <= PETScIter) then totalIter = totalIter + 1 print'(1x,a,3(a,i0))', trim(incInfo), ' @ Iteration ', num%itmin, '≤',totalIter, '≤', num%itmax - if(debugRotation) & - write(IO_STDOUT,'(/,a,/,3(3(f12.7,1x)/))',advance='no') & - ' deformation gradient aim (lab) =', transpose(params%rotation_BC%rotate(F_aim,active=.true.)) - write(IO_STDOUT,'(/,a,/,3(3(f12.7,1x)/))',advance='no') & - ' deformation gradient aim =', transpose(F_aim) + if (debugRotation) print'(/,a,/,2(3(f12.7,1x)/),3(f12.7,1x))', & + ' deformation gradient aim (lab) =', transpose(params%rotation_BC%rotate(F_aim,active=.true.)) + print'(/,a,/,2(3(f12.7,1x)/),3(f12.7,1x))', & + ' deformation gradient aim =', transpose(F_aim) flush(IO_STDOUT) endif newIteration @@ -607,7 +603,7 @@ subroutine formResidual(in, FandF_tau, & do k = 1, grid3; do j = 1, grid(2); do i = 1, grid(1) e = e + 1 residual_F(1:3,1:3,i,j,k) = & - math_mul3333xx33(math_invSym3333(homogenization_dPdF(1:3,1:3,1:3,1:3,1,e) + C_scale), & + math_mul3333xx33(math_invSym3333(homogenization_dPdF(1:3,1:3,1:3,1:3,e) + C_scale), & residual_F(1:3,1:3,i,j,k) - matmul(F(1:3,1:3,i,j,k), & math_mul3333xx33(C_scale,F_tau(1:3,1:3,i,j,k) - F(1:3,1:3,i,j,k) - math_I3))) & + residual_F_tau(1:3,1:3,i,j,k) diff --git a/src/grid/grid_thermal_spectral.f90 b/src/grid/grid_thermal_spectral.f90 index 68a1c5ed1..259b45f33 100644 --- a/src/grid/grid_thermal_spectral.f90 +++ b/src/grid/grid_thermal_spectral.f90 @@ -131,8 +131,7 @@ subroutine grid_thermal_spectral_init cell = 0 do k = 1, grid3; do j = 1, grid(2); do i = 1,grid(1) cell = cell + 1 - T_current(i,j,k) = temperature(material_homogenizationAt(cell))% & - p(thermalMapping(material_homogenizationAt(cell))%p(1,cell)) + T_current(i,j,k) = temperature(material_homogenizationAt(cell))%p(material_homogenizationMemberAt(1,cell)) T_lastInc(i,j,k) = T_current(i,j,k) T_stagInc(i,j,k) = T_current(i,j,k) enddo; enddo; enddo @@ -197,8 +196,7 @@ function grid_thermal_spectral_solution(timeinc) result(solution) call VecMax(solution_vec,devNull,T_max,ierr); CHKERRQ(ierr) if (solution%converged) & print'(/,a)', ' ... thermal conduction converged ..................................' - write(IO_STDOUT,'(/,a,f8.4,2x,f8.4,2x,f8.4,/)',advance='no') ' Minimum|Maximum|Delta Temperature / K = ',& - T_min, T_max, stagNorm + print'(/,a,f8.4,2x,f8.4,2x,f8.4)', ' Minimum|Maximum|Delta Temperature / K = ', T_min, T_max, stagNorm print'(/,a)', ' ===========================================================================' flush(IO_STDOUT) diff --git a/src/grid/spectral_utilities.f90 b/src/grid/spectral_utilities.f90 index 1e1608d7c..e8bae223a 100644 --- a/src/grid/spectral_utilities.f90 +++ b/src/grid/spectral_utilities.f90 @@ -93,7 +93,7 @@ module spectral_utilities real(pReal), dimension(3,3) :: stress_BC logical, dimension(3,3) :: stress_mask type(rotation) :: rotation_BC - real(pReal) :: timeinc, timeincOld + real(pReal) :: timeinc end type tSolutionParams type :: tNumerics @@ -688,8 +688,8 @@ function utilities_maskedCompliance(rot_BC,mask_stress,C) if(debugGeneral) then print'(/,a)', ' ... updating masked compliance ............................................' - write(IO_STDOUT,'(/,a,/,9(9(2x,f12.7,1x)/))',advance='no') ' Stiffness C (load) / GPa =',& - transpose(temp99_Real)*1.0e-9_pReal + print'(/,a,/,8(9(2x,f12.7,1x)/),9(2x,f12.7,1x))', & + ' Stiffness C (load) / GPa =', transpose(temp99_Real)*1.0e-9_pReal flush(IO_STDOUT) endif @@ -709,9 +709,8 @@ function utilities_maskedCompliance(rot_BC,mask_stress,C) if (debugGeneral .or. errmatinv) then write(formatString, '(i2)') size_reduced formatString = '(/,a,/,'//trim(formatString)//'('//trim(formatString)//'(2x,es9.2,1x)/))' - write(IO_STDOUT,trim(formatString),advance='no') ' C * S (load) ', & - transpose(matmul(c_reduced,s_reduced)) - write(IO_STDOUT,trim(formatString),advance='no') ' S (load) ', transpose(s_reduced) + print trim(formatString), ' C * S (load) ', transpose(matmul(c_reduced,s_reduced)) + print trim(formatString), ' S (load) ', transpose(s_reduced) if(errmatinv) error stop 'matrix inversion error' endif temp99_real = reshape(unpack(reshape(s_reduced,[size_reduced**2]),reshape(mask,[81]),0.0_pReal),[9,9]) @@ -722,7 +721,7 @@ function utilities_maskedCompliance(rot_BC,mask_stress,C) utilities_maskedCompliance = math_99to3333(temp99_Real) if(debugGeneral) then - write(IO_STDOUT,'(/,a,/,9(9(2x,f10.5,1x)/),/)',advance='no') & + print'(/,a,/,9(9(2x,f10.5,1x)/),9(2x,f10.5,1x))', & ' Masked Compliance (load) * GPa =', transpose(temp99_Real)*1.0e9_pReal flush(IO_STDOUT) endif @@ -811,20 +810,18 @@ subroutine utilities_constitutiveResponse(P,P_av,C_volAvg,C_minmaxAvg,& print'(/,a)', ' ... evaluating constitutive response ......................................' flush(IO_STDOUT) - homogenization_F = reshape(F,[3,3,1,product(grid(1:2))*grid3]) ! set materialpoint target F to estimated field + homogenization_F = reshape(F,[3,3,product(grid(1:2))*grid3]) ! set materialpoint target F to estimated field - call materialpoint_stressAndItsTangent(timeinc) ! calculate P field + call materialpoint_stressAndItsTangent(timeinc,[1,1],[1,product(grid(1:2))*grid3]) ! calculate P field P = reshape(homogenization_P, [3,3,grid(1),grid(2),grid3]) P_av = sum(sum(sum(P,dim=5),dim=4),dim=3) * wgt ! average of P call MPI_Allreduce(MPI_IN_PLACE,P_av,9,MPI_DOUBLE,MPI_SUM,PETSC_COMM_WORLD,ierr) - if (debugRotation) & - write(IO_STDOUT,'(/,a,/,3(3(2x,f12.4,1x)/))',advance='no') ' Piola--Kirchhoff stress (lab) / MPa =',& - transpose(P_av)*1.e-6_pReal - if(present(rotation_BC)) & - P_av = rotation_BC%rotate(P_av) - write(IO_STDOUT,'(/,a,/,3(3(2x,f12.4,1x)/))',advance='no') ' Piola--Kirchhoff stress / MPa =',& - transpose(P_av)*1.e-6_pReal + if (debugRotation) print'(/,a,/,2(3(2x,f12.4,1x)/),3(2x,f12.4,1x))', & + ' Piola--Kirchhoff stress (lab) / MPa =', transpose(P_av)*1.e-6_pReal + if(present(rotation_BC)) P_av = rotation_BC%rotate(P_av) + print'(/,a,/,2(3(2x,f12.4,1x)/),3(2x,f12.4,1x))', & + ' Piola--Kirchhoff stress / MPa =', transpose(P_av)*1.e-6_pReal flush(IO_STDOUT) dPdF_max = 0.0_pReal @@ -832,13 +829,13 @@ subroutine utilities_constitutiveResponse(P,P_av,C_volAvg,C_minmaxAvg,& dPdF_min = huge(1.0_pReal) dPdF_norm_min = huge(1.0_pReal) do i = 1, product(grid(1:2))*grid3 - if (dPdF_norm_max < sum(homogenization_dPdF(1:3,1:3,1:3,1:3,1,i)**2.0_pReal)) then - dPdF_max = homogenization_dPdF(1:3,1:3,1:3,1:3,1,i) - dPdF_norm_max = sum(homogenization_dPdF(1:3,1:3,1:3,1:3,1,i)**2.0_pReal) + if (dPdF_norm_max < sum(homogenization_dPdF(1:3,1:3,1:3,1:3,i)**2.0_pReal)) then + dPdF_max = homogenization_dPdF(1:3,1:3,1:3,1:3,i) + dPdF_norm_max = sum(homogenization_dPdF(1:3,1:3,1:3,1:3,i)**2.0_pReal) endif - if (dPdF_norm_min > sum(homogenization_dPdF(1:3,1:3,1:3,1:3,1,i)**2.0_pReal)) then - dPdF_min = homogenization_dPdF(1:3,1:3,1:3,1:3,1,i) - dPdF_norm_min = sum(homogenization_dPdF(1:3,1:3,1:3,1:3,1,i)**2.0_pReal) + if (dPdF_norm_min > sum(homogenization_dPdF(1:3,1:3,1:3,1:3,i)**2.0_pReal)) then + dPdF_min = homogenization_dPdF(1:3,1:3,1:3,1:3,i) + dPdF_norm_min = sum(homogenization_dPdF(1:3,1:3,1:3,1:3,i)**2.0_pReal) endif end do @@ -856,7 +853,7 @@ subroutine utilities_constitutiveResponse(P,P_av,C_volAvg,C_minmaxAvg,& C_minmaxAvg = 0.5_pReal*(dPdF_max + dPdF_min) - C_volAvg = sum(sum(homogenization_dPdF,dim=6),dim=5) + C_volAvg = sum(homogenization_dPdF,dim=5) call MPI_Allreduce(MPI_IN_PLACE,C_volAvg,81,MPI_DOUBLE,MPI_SUM,PETSC_COMM_WORLD,ierr) if (ierr /= 0) error stop 'MPI error' C_volAvg = C_volAvg * wgt diff --git a/src/homogenization.f90 b/src/homogenization.f90 index 347634212..52553b57b 100644 --- a/src/homogenization.f90 +++ b/src/homogenization.f90 @@ -11,14 +11,10 @@ module homogenization use math use material use constitutive - use crystallite - use FEsolving use discretization use thermal_isothermal - use thermal_adiabatic use thermal_conduction use damage_none - use damage_local use damage_nonlocal use results @@ -30,14 +26,16 @@ module homogenization !-------------------------------------------------------------------------------------------------- ! General variables for the homogenization at a material point - real(pReal), dimension(:,:,:,:), allocatable, public :: & - homogenization_F0, & !< def grad of IP at start of FE increment - homogenization_F !< def grad of IP to be reached at end of FE increment - real(pReal), dimension(:,:,:,:), allocatable, public, protected :: & - homogenization_P !< first P--K stress of IP - real(pReal), dimension(:,:,:,:,:,:), allocatable, public, protected :: & - homogenization_dPdF !< tangent of first P--K stress at IP + real(pReal), dimension(:,:,:), allocatable, public :: & + homogenization_F0, & !< def grad of IP at start of FE increment + homogenization_F !< def grad of IP to be reached at end of FE increment + real(pReal), dimension(:,:,:), allocatable, public :: & !, protected :: & Issue with ifort + homogenization_P !< first P--K stress of IP + real(pReal), dimension(:,:,:,:,:), allocatable, public :: & !, protected :: & + homogenization_dPdF !< tangent of first P--K stress at IP + +!-------------------------------------------------------------------------------------------------- type :: tNumerics integer :: & nMPstate !< materialpoint state loop limit @@ -49,90 +47,50 @@ module homogenization type(tNumerics) :: num - type :: tDebugOptions - logical :: & - basic, & - extensive, & - selective - integer :: & - element, & - ip, & - grain - end type tDebugOptions - - type(tDebugOptions) :: debugHomog - +!-------------------------------------------------------------------------------------------------- interface - module subroutine mech_none_init - end subroutine mech_none_init - - module subroutine mech_isostrain_init - end subroutine mech_isostrain_init - - module subroutine mech_RGC_init(num_homogMech) + module subroutine mech_init(num_homog) class(tNode), pointer, intent(in) :: & - num_homogMech !< pointer to mechanical homogenization numerics data - end subroutine mech_RGC_init + num_homog !< pointer to mechanical homogenization numerics data + end subroutine mech_init - - module subroutine mech_isostrain_partitionDeformation(F,avgF) - real(pReal), dimension (:,:,:), intent(out) :: F !< partitioned deformation gradient - real(pReal), dimension (3,3), intent(in) :: avgF !< average deformation gradient at material point - end subroutine mech_isostrain_partitionDeformation - - module subroutine mech_RGC_partitionDeformation(F,avgF,instance,of) - real(pReal), dimension (:,:,:), intent(out) :: F !< partitioned deformation gradient - real(pReal), dimension (3,3), intent(in) :: avgF !< average deformation gradient at material point - integer, intent(in) :: & - instance, & - of - end subroutine mech_RGC_partitionDeformation - - - module subroutine mech_isostrain_averageStressAndItsTangent(avgP,dAvgPdAvgF,P,dPdF,instance) - real(pReal), dimension (3,3), intent(out) :: avgP !< average stress at material point - real(pReal), dimension (3,3,3,3), intent(out) :: dAvgPdAvgF !< average stiffness at material point - - real(pReal), dimension (:,:,:), intent(in) :: P !< partitioned stresses - real(pReal), dimension (:,:,:,:,:), intent(in) :: dPdF !< partitioned stiffnesses - integer, intent(in) :: instance - end subroutine mech_isostrain_averageStressAndItsTangent - - module subroutine mech_RGC_averageStressAndItsTangent(avgP,dAvgPdAvgF,P,dPdF,instance) - real(pReal), dimension (3,3), intent(out) :: avgP !< average stress at material point - real(pReal), dimension (3,3,3,3), intent(out) :: dAvgPdAvgF !< average stiffness at material point - - real(pReal), dimension (:,:,:), intent(in) :: P !< partitioned stresses - real(pReal), dimension (:,:,:,:,:), intent(in) :: dPdF !< partitioned stiffnesses - integer, intent(in) :: instance - end subroutine mech_RGC_averageStressAndItsTangent - - module function mech_RGC_updateState(P,F,F0,avgF,dt,dPdF,ip,el) - logical, dimension(2) :: mech_RGC_updateState - real(pReal), dimension(:,:,:), intent(in) :: & - P,& !< partitioned stresses - F,& !< partitioned deformation gradients - F0 !< partitioned initial deformation gradients - real(pReal), dimension(:,:,:,:,:), intent(in) :: dPdF !< partitioned stiffnesses - real(pReal), dimension(3,3), intent(in) :: avgF !< average F - real(pReal), intent(in) :: dt !< time increment - integer, intent(in) :: & - ip, & !< integration point number + module subroutine mech_partition(subF,ip,el) + real(pReal), intent(in), dimension(3,3) :: & + subF + integer, intent(in) :: & + ip, & !< integration point el !< element number - end function mech_RGC_updateState + end subroutine mech_partition + module subroutine mech_homogenize(ip,el) + integer, intent(in) :: & + ip, & !< integration point + el !< element number + end subroutine mech_homogenize - module subroutine mech_RGC_results(instance,group) - integer, intent(in) :: instance !< homogenization instance - character(len=*), intent(in) :: group !< group name in HDF5 file - end subroutine mech_RGC_results + module subroutine mech_results(group_base,h) + character(len=*), intent(in) :: group_base + integer, intent(in) :: h + end subroutine mech_results + + module function mech_updateState(subdt,subF,ip,el) result(doneAndHappy) + real(pReal), intent(in) :: & + subdt !< current time step + real(pReal), intent(in), dimension(3,3) :: & + subF + integer, intent(in) :: & + ip, & !< integration point + el !< element number + logical, dimension(2) :: doneAndHappy + end function mech_updateState end interface public :: & homogenization_init, & materialpoint_stressAndItsTangent, & + homogenization_forward, & homogenization_results contains @@ -145,49 +103,13 @@ subroutine homogenization_init class (tNode) , pointer :: & num_homog, & - num_homogMech, & - num_homogGeneric, & - debug_homogenization - - debug_homogenization => config_debug%get('homogenization', defaultVal=emptyList) - debugHomog%basic = debug_homogenization%contains('basic') - debugHomog%extensive = debug_homogenization%contains('extensive') - debugHomog%selective = debug_homogenization%contains('selective') - debugHomog%element = config_debug%get_asInt('element',defaultVal = 1) - debugHomog%ip = config_debug%get_asInt('integrationpoint',defaultVal = 1) - debugHomog%grain = config_debug%get_asInt('grain',defaultVal = 1) - - if (debugHomog%grain < 1 & - .or. debugHomog%grain > homogenization_Nconstituents(material_homogenizationAt(debugHomog%element))) & - call IO_error(602,ext_msg='constituent', el=debugHomog%element, g=debugHomog%grain) - - - num_homog => config_numerics%get('homogenization',defaultVal=emptyDict) - num_homogMech => num_homog%get('mech',defaultVal=emptyDict) - num_homogGeneric => num_homog%get('generic',defaultVal=emptyDict) - - if (any(homogenization_type == HOMOGENIZATION_NONE_ID)) call mech_none_init - if (any(homogenization_type == HOMOGENIZATION_ISOSTRAIN_ID)) call mech_isostrain_init - if (any(homogenization_type == HOMOGENIZATION_RGC_ID)) call mech_RGC_init(num_homogMech) - - if (any(thermal_type == THERMAL_isothermal_ID)) call thermal_isothermal_init - if (any(thermal_type == THERMAL_adiabatic_ID)) call thermal_adiabatic_init - if (any(thermal_type == THERMAL_conduction_ID)) call thermal_conduction_init - - if (any(damage_type == DAMAGE_none_ID)) call damage_none_init - if (any(damage_type == DAMAGE_local_ID)) call damage_local_init - if (any(damage_type == DAMAGE_nonlocal_ID)) call damage_nonlocal_init - - -!-------------------------------------------------------------------------------------------------- -! allocate and initialize global variables - allocate(homogenization_dPdF(3,3,3,3,discretization_nIPs,discretization_Nelems), source=0.0_pReal) - homogenization_F0 = spread(spread(math_I3,3,discretization_nIPs),4,discretization_Nelems) ! initialize to identity - homogenization_F = homogenization_F0 ! initialize to identity - allocate(homogenization_P(3,3,discretization_nIPs,discretization_Nelems), source=0.0_pReal) + num_homogGeneric print'(/,a)', ' <<<+- homogenization init -+>>>'; flush(IO_STDOUT) + num_homog => config_numerics%get('homogenization',defaultVal=emptyDict) + num_homogGeneric => num_homog%get('generic',defaultVal=emptyDict) + num%nMPstate = num_homogGeneric%get_asInt ('nMPstate', defaultVal=10) num%subStepMinHomog = num_homogGeneric%get_asFloat('subStepMin', defaultVal=1.0e-3_pReal) num%subStepSizeHomog = num_homogGeneric%get_asFloat('subStepSize', defaultVal=0.25_pReal) @@ -198,190 +120,146 @@ subroutine homogenization_init if (num%subStepSizeHomog <= 0.0_pReal) call IO_error(301,ext_msg='subStepSizeHomog') if (num%stepIncreaseHomog <= 0.0_pReal) call IO_error(301,ext_msg='stepIncreaseHomog') + + call mech_init(num_homog) + + if (any(thermal_type == THERMAL_isothermal_ID)) call thermal_isothermal_init + if (any(thermal_type == THERMAL_conduction_ID)) call thermal_conduction_init + + if (any(damage_type == DAMAGE_none_ID)) call damage_none_init + if (any(damage_type == DAMAGE_nonlocal_ID)) call damage_nonlocal_init + + end subroutine homogenization_init !-------------------------------------------------------------------------------------------------- !> @brief parallelized calculation of stress and corresponding tangent at material points !-------------------------------------------------------------------------------------------------- -subroutine materialpoint_stressAndItsTangent(dt) +subroutine materialpoint_stressAndItsTangent(dt,FEsolving_execIP,FEsolving_execElem) real(pReal), intent(in) :: dt !< time increment + integer, dimension(2), intent(in) :: FEsolving_execElem, FEsolving_execIP integer :: & - NiterationHomog, & NiterationMPstate, & - i, & !< integration point number - e, & !< element number - myNgrains - real(pReal), dimension(discretization_nIPs,discretization_Nelems) :: & + ip, & !< integration point number + el, & !< element number + myNgrains, co, ce, ho, me + real(pReal) :: & subFrac, & subStep - logical, dimension(discretization_nIPs,discretization_Nelems) :: & - requested, & + logical :: & converged - logical, dimension(2,discretization_nIPs,discretization_Nelems) :: & + logical, dimension(2) :: & doneAndHappy + !$OMP PARALLEL DO PRIVATE(ce,me,ho,myNgrains,NiterationMPstate,subFrac,converged,subStep,doneAndHappy) + do el = FEsolving_execElem(1),FEsolving_execElem(2) + ho = material_homogenizationAt(el) + myNgrains = homogenization_Nconstituents(ho) + do ip = FEsolving_execIP(1),FEsolving_execIP(2) + me = material_homogenizationMemberAt(ip,el) !-------------------------------------------------------------------------------------------------- ! initialize restoration points - do e = FEsolving_execElem(1),FEsolving_execElem(2) - do i = FEsolving_execIP(1),FEsolving_execIP(2); + call constitutive_initializeRestorationPoints(ip,el) - call crystallite_initializeRestorationPoints(i,e) + subFrac = 0.0_pReal + converged = .false. ! pretend failed step ... + subStep = 1.0_pReal/num%subStepSizeHomog ! ... larger then the requested calculation - subFrac(i,e) = 0.0_pReal - converged(i,e) = .false. ! pretend failed step ... - subStep(i,e) = 1.0_pReal/num%subStepSizeHomog ! ... larger then the requested calculation - requested(i,e) = .true. ! everybody requires calculation + if (homogState(ho)%sizeState > 0) & + homogState(ho)%subState0(:,me) = homogState(ho)%State0(:,me) + if (damageState(ho)%sizeState > 0) & + damageState(ho)%subState0(:,me) = damageState(ho)%State0(:,me) - if (homogState(material_homogenizationAt(e))%sizeState > 0) & - homogState(material_homogenizationAt(e))%subState0(:,material_homogenizationMemberAt(i,e)) = & - homogState(material_homogenizationAt(e))%State0( :,material_homogenizationMemberAt(i,e)) + cutBackLooping: do while (.not. terminallyIll .and. subStep > num%subStepMinHomog) - if (thermalState(material_homogenizationAt(e))%sizeState > 0) & - thermalState(material_homogenizationAt(e))%subState0(:,material_homogenizationMemberAt(i,e)) = & - thermalState(material_homogenizationAt(e))%State0( :,material_homogenizationMemberAt(i,e)) + if (converged) then + subFrac = subFrac + subStep + subStep = min(1.0_pReal-subFrac,num%stepIncreaseHomog*subStep) ! introduce flexibility for step increase/acceleration - if (damageState(material_homogenizationAt(e))%sizeState > 0) & - damageState(material_homogenizationAt(e))%subState0(:,material_homogenizationMemberAt(i,e)) = & - damageState(material_homogenizationAt(e))%State0( :,material_homogenizationMemberAt(i,e)) - enddo - enddo - - NiterationHomog = 0 - - cutBackLooping: do while (.not. terminallyIll .and. & - any(subStep(FEsolving_execIP(1):FEsolving_execIP(2),& - FEsolving_execElem(1):FEsolving_execElem(2)) > num%subStepMinHomog)) - - !$OMP PARALLEL DO - elementLooping1: do e = FEsolving_execElem(1),FEsolving_execElem(2) - myNgrains = homogenization_Nconstituents(material_homogenizationAt(e)) - IpLooping1: do i = FEsolving_execIP(1),FEsolving_execIP(2) - - if (converged(i,e)) then - subFrac(i,e) = subFrac(i,e) + subStep(i,e) - subStep(i,e) = min(1.0_pReal-subFrac(i,e),num%stepIncreaseHomog*subStep(i,e)) ! introduce flexibility for step increase/acceleration - - steppingNeeded: if (subStep(i,e) > num%subStepMinHomog) then + steppingNeeded: if (subStep > num%subStepMinHomog) then ! wind forward grain starting point - call crystallite_windForward(i,e) + call constitutive_windForward(ip,el) - if(homogState(material_homogenizationAt(e))%sizeState > 0) & - homogState(material_homogenizationAt(e))%subState0(:,material_homogenizationMemberAt(i,e)) = & - homogState(material_homogenizationAt(e))%State (:,material_homogenizationMemberAt(i,e)) - if(thermalState(material_homogenizationAt(e))%sizeState > 0) & - thermalState(material_homogenizationAt(e))%subState0(:,material_homogenizationMemberAt(i,e)) = & - thermalState(material_homogenizationAt(e))%State (:,material_homogenizationMemberAt(i,e)) - if(damageState(material_homogenizationAt(e))%sizeState > 0) & - damageState(material_homogenizationAt(e))%subState0(:,material_homogenizationMemberAt(i,e)) = & - damageState(material_homogenizationAt(e))%State (:,material_homogenizationMemberAt(i,e)) + if(homogState(ho)%sizeState > 0) & + homogState(ho)%subState0(:,me) = homogState(ho)%State(:,me) + if(damageState(ho)%sizeState > 0) & + damageState(ho)%subState0(:,me) = damageState(ho)%State(:,me) endif steppingNeeded - - else - if ( (myNgrains == 1 .and. subStep(i,e) <= 1.0 ) .or. & ! single grain already tried internal subStepping in crystallite - num%subStepSizeHomog * subStep(i,e) <= num%subStepMinHomog ) then ! would require too small subStep + elseif ( (myNgrains == 1 .and. subStep <= 1.0 ) .or. & ! single grain already tried internal subStepping in crystallite + num%subStepSizeHomog * subStep <= num%subStepMinHomog ) then ! would require too small subStep ! cutback makes no sense - if (.not. terminallyIll) then ! so first signals terminally ill... - print*, ' Integration point ', i,' at element ', e, ' terminally ill' - endif - terminallyIll = .true. ! ...and kills all others - else ! cutback makes sense - subStep(i,e) = num%subStepSizeHomog * subStep(i,e) ! crystallite had severe trouble, so do a significant cutback + if (.not. terminallyIll) & ! so first signals terminally ill... + print*, ' Integration point ', ip,' at element ', el, ' terminally ill' + terminallyIll = .true. ! ...and kills all others + else ! cutback makes sense + subStep = num%subStepSizeHomog * subStep ! crystallite had severe trouble, so do a significant cutback - call crystallite_restore(i,e,subStep(i,e) < 1.0_pReal) + call constitutive_restore(ip,el,subStep < 1.0_pReal) - if(homogState(material_homogenizationAt(e))%sizeState > 0) & - homogState(material_homogenizationAt(e))%State( :,material_homogenizationMemberAt(i,e)) = & - homogState(material_homogenizationAt(e))%subState0(:,material_homogenizationMemberAt(i,e)) - if(thermalState(material_homogenizationAt(e))%sizeState > 0) & - thermalState(material_homogenizationAt(e))%State( :,material_homogenizationMemberAt(i,e)) = & - thermalState(material_homogenizationAt(e))%subState0(:,material_homogenizationMemberAt(i,e)) - if(damageState(material_homogenizationAt(e))%sizeState > 0) & - damageState(material_homogenizationAt(e))%State( :,material_homogenizationMemberAt(i,e)) = & - damageState(material_homogenizationAt(e))%subState0(:,material_homogenizationMemberAt(i,e)) - endif + if(homogState(ho)%sizeState > 0) & + homogState(ho)%State(:,me) = homogState(ho)%subState0(:,me) + if(damageState(ho)%sizeState > 0) & + damageState(ho)%State(:,me) = damageState(ho)%subState0(:,me) endif - if (subStep(i,e) > num%subStepMinHomog) then - requested(i,e) = .true. - doneAndHappy(1:2,i,e) = [.false.,.true.] - endif - enddo IpLooping1 - enddo elementLooping1 - !$OMP END PARALLEL DO + if (subStep > num%subStepMinHomog) doneAndHappy = [.false.,.true.] - NiterationMPstate = 0 - - convergenceLooping: do while (.not. terminallyIll .and. & - any( requested(:,FEsolving_execELem(1):FEsolving_execElem(2)) & - .and. .not. doneAndHappy(1,:,FEsolving_execELem(1):FEsolving_execElem(2)) & - ) .and. & - NiterationMPstate < num%nMPstate) - NiterationMPstate = NiterationMPstate + 1 + NiterationMPstate = 0 + convergenceLooping: do while (.not. terminallyIll & + .and. .not. doneAndHappy(1) & + .and. NiterationMPstate < num%nMPstate) + NiterationMPstate = NiterationMPstate + 1 !-------------------------------------------------------------------------------------------------- ! deformation partitioning - !$OMP PARALLEL DO PRIVATE(myNgrains) - elementLooping2: do e = FEsolving_execElem(1),FEsolving_execElem(2) - myNgrains = homogenization_Nconstituents(material_homogenizationAt(e)) - IpLooping2: do i = FEsolving_execIP(1),FEsolving_execIP(2) - if(requested(i,e) .and. .not. doneAndHappy(1,i,e)) then ! requested but not yet done - call partitionDeformation(homogenization_F0(1:3,1:3,i,e) & - + (homogenization_F(1:3,1:3,i,e)-homogenization_F0(1:3,1:3,i,e))& - *(subStep(i,e)+subFrac(i,e)), & - i,e) - crystallite_dt(1:myNgrains,i,e) = dt*subStep(i,e) ! propagate materialpoint dt to grains - crystallite_requested(1:myNgrains,i,e) = .true. ! request calculation for constituents - else - crystallite_requested(1:myNgrains,i,e) = .false. ! calculation for constituents not required anymore - endif - enddo IpLooping2 - enddo elementLooping2 - !$OMP END PARALLEL DO -!-------------------------------------------------------------------------------------------------- -! crystallite integration - converged = crystallite_stress() !ToDo: MD not sure if that is the best logic + if (.not. doneAndHappy(1)) then + ce = (el-1)*discretization_nIPs + ip + call mech_partition(homogenization_F0(1:3,1:3,ce) & + + (homogenization_F(1:3,1:3,ce)-homogenization_F0(1:3,1:3,ce))& + *(subStep+subFrac), & + ip,el) + converged = .true. + do co = 1, myNgrains + converged = converged .and. crystallite_stress(dt*subStep,co,ip,el) + enddo -!-------------------------------------------------------------------------------------------------- -! state update - !$OMP PARALLEL DO - elementLooping3: do e = FEsolving_execElem(1),FEsolving_execElem(2) - IpLooping3: do i = FEsolving_execIP(1),FEsolving_execIP(2) - if (requested(i,e) .and. .not. doneAndHappy(1,i,e)) then - if (.not. converged(i,e)) then - doneAndHappy(1:2,i,e) = [.true.,.false.] + if (.not. converged) then + doneAndHappy = [.true.,.false.] else - doneAndHappy(1:2,i,e) = updateState(dt*subStep(i,e), & - homogenization_F0(1:3,1:3,i,e) & - + (homogenization_F(1:3,1:3,i,e)-homogenization_F0(1:3,1:3,i,e)) & - *(subStep(i,e)+subFrac(i,e)), & - i,e) - converged(i,e) = all(doneAndHappy(1:2,i,e)) ! converged if done and happy + ce = (el-1)*discretization_nIPs + ip + doneAndHappy = mech_updateState(dt*subStep, & + homogenization_F0(1:3,1:3,ce) & + + (homogenization_F(1:3,1:3,ce)-homogenization_F0(1:3,1:3,ce)) & + *(subStep+subFrac), & + ip,el) + converged = all(doneAndHappy) endif endif - enddo IpLooping3 - enddo elementLooping3 - !$OMP END PARALLEL DO - enddo convergenceLooping - - NiterationHomog = NiterationHomog + 1 - - enddo cutBackLooping + enddo convergenceLooping + enddo cutBackLooping + enddo + enddo + !$OMP END PARALLEL DO if (.not. terminallyIll ) then - call crystallite_orientations() ! calculate crystal orientations - !$OMP PARALLEL DO - elementLooping4: do e = FEsolving_execElem(1),FEsolving_execElem(2) - IpLooping4: do i = FEsolving_execIP(1),FEsolving_execIP(2) - call averageStressAndItsTangent(i,e) - enddo IpLooping4 - enddo elementLooping4 + !$OMP PARALLEL DO PRIVATE(ho,myNgrains) + elementLooping3: do el = FEsolving_execElem(1),FEsolving_execElem(2) + ho = material_homogenizationAt(el) + myNgrains = homogenization_Nconstituents(ho) + IpLooping3: do ip = FEsolving_execIP(1),FEsolving_execIP(2) + do co = 1, myNgrains + call crystallite_orientations(co,ip,el) + enddo + call mech_homogenize(ip,el) + enddo IpLooping3 + enddo elementLooping3 !$OMP END PARALLEL DO else print'(/,a,/)', ' << HOMOG >> Material Point terminally ill' @@ -390,189 +268,56 @@ subroutine materialpoint_stressAndItsTangent(dt) end subroutine materialpoint_stressAndItsTangent -!-------------------------------------------------------------------------------------------------- -!> @brief partition material point def grad onto constituents -!-------------------------------------------------------------------------------------------------- -subroutine partitionDeformation(subF,ip,el) - - real(pReal), intent(in), dimension(3,3) :: & - subF - integer, intent(in) :: & - ip, & !< integration point - el !< element number - - chosenHomogenization: select case(homogenization_type(material_homogenizationAt(el))) - - case (HOMOGENIZATION_NONE_ID) chosenHomogenization - crystallite_partitionedF(1:3,1:3,1,ip,el) = subF - - case (HOMOGENIZATION_ISOSTRAIN_ID) chosenHomogenization - call mech_isostrain_partitionDeformation(& - crystallite_partitionedF(1:3,1:3,1:homogenization_Nconstituents(material_homogenizationAt(el)),ip,el), & - subF) - - case (HOMOGENIZATION_RGC_ID) chosenHomogenization - call mech_RGC_partitionDeformation(& - crystallite_partitionedF(1:3,1:3,1:homogenization_Nconstituents(material_homogenizationAt(el)),ip,el), & - subF,& - ip, & - el) - end select chosenHomogenization - -end subroutine partitionDeformation - - -!-------------------------------------------------------------------------------------------------- -!> @brief update the internal state of the homogenization scheme and tell whether "done" and -!> "happy" with result -!-------------------------------------------------------------------------------------------------- -function updateState(subdt,subF,ip,el) - - real(pReal), intent(in) :: & - subdt !< current time step - real(pReal), intent(in), dimension(3,3) :: & - subF - integer, intent(in) :: & - ip, & !< integration point - el !< element number - integer :: c - logical, dimension(2) :: updateState - real(pReal) :: dPdFs(3,3,3,3,homogenization_Nconstituents(material_homogenizationAt(el))) - - updateState = .true. - chosenHomogenization: select case(homogenization_type(material_homogenizationAt(el))) - case (HOMOGENIZATION_RGC_ID) chosenHomogenization - do c=1,homogenization_Nconstituents(material_homogenizationAt(el)) - dPdFs(:,:,:,:,c) = crystallite_stressTangent(c,ip,el) - enddo - updateState = & - updateState .and. & - mech_RGC_updateState(crystallite_P(1:3,1:3,1:homogenization_Nconstituents(material_homogenizationAt(el)),ip,el), & - crystallite_partitionedF(1:3,1:3,1:homogenization_Nconstituents(material_homogenizationAt(el)),ip,el), & - crystallite_partitionedF0(1:3,1:3,1:homogenization_Nconstituents(material_homogenizationAt(el)),ip,el),& - subF,& - subdt, & - dPdFs, & - ip, & - el) - end select chosenHomogenization - - chosenThermal: select case (thermal_type(material_homogenizationAt(el))) - case (THERMAL_adiabatic_ID) chosenThermal - updateState = & - updateState .and. & - thermal_adiabatic_updateState(subdt, & - ip, & - el) - end select chosenThermal - - chosenDamage: select case (damage_type(material_homogenizationAt(el))) - case (DAMAGE_local_ID) chosenDamage - updateState = & - updateState .and. & - damage_local_updateState(subdt, & - ip, & - el) - end select chosenDamage - -end function updateState - - -!-------------------------------------------------------------------------------------------------- -!> @brief derive average stress and stiffness from constituent quantities -!-------------------------------------------------------------------------------------------------- -subroutine averageStressAndItsTangent(ip,el) - - integer, intent(in) :: & - ip, & !< integration point - el !< element number - integer :: c - real(pReal) :: dPdFs(3,3,3,3,homogenization_Nconstituents(material_homogenizationAt(el))) - - - chosenHomogenization: select case(homogenization_type(material_homogenizationAt(el))) - case (HOMOGENIZATION_NONE_ID) chosenHomogenization - homogenization_P(1:3,1:3,ip,el) = crystallite_P(1:3,1:3,1,ip,el) - homogenization_dPdF(1:3,1:3,1:3,1:3,ip,el) = crystallite_stressTangent(1,ip,el) - - case (HOMOGENIZATION_ISOSTRAIN_ID) chosenHomogenization - do c = 1, homogenization_Nconstituents(material_homogenizationAt(el)) - dPdFs(:,:,:,:,c) = crystallite_stressTangent(c,ip,el) - enddo - call mech_isostrain_averageStressAndItsTangent(& - homogenization_P(1:3,1:3,ip,el), & - homogenization_dPdF(1:3,1:3,1:3,1:3,ip,el),& - crystallite_P(1:3,1:3,1:homogenization_Nconstituents(material_homogenizationAt(el)),ip,el), & - dPdFs, & - homogenization_typeInstance(material_homogenizationAt(el))) - - case (HOMOGENIZATION_RGC_ID) chosenHomogenization - do c = 1, homogenization_Nconstituents(material_homogenizationAt(el)) - dPdFs(:,:,:,:,c) = crystallite_stressTangent(c,ip,el) - enddo - call mech_RGC_averageStressAndItsTangent(& - homogenization_P(1:3,1:3,ip,el), & - homogenization_dPdF(1:3,1:3,1:3,1:3,ip,el),& - crystallite_P(1:3,1:3,1:homogenization_Nconstituents(material_homogenizationAt(el)),ip,el), & - dPdFs, & - homogenization_typeInstance(material_homogenizationAt(el))) - end select chosenHomogenization - -end subroutine averageStressAndItsTangent - - !-------------------------------------------------------------------------------------------------- !> @brief writes homogenization results to HDF5 output file !-------------------------------------------------------------------------------------------------- subroutine homogenization_results - use material, only: & - material_homogenization_type => homogenization_type - integer :: p + integer :: ho character(len=:), allocatable :: group_base,group - !real(pReal), dimension(:,:,:), allocatable :: temp - do p=1,size(material_name_homogenization) - group_base = 'current/homogenization/'//trim(material_name_homogenization(p)) + call results_closeGroup(results_addGroup('current/homogenization/')) + + do ho=1,size(material_name_homogenization) + group_base = 'current/homogenization/'//trim(material_name_homogenization(ho)) call results_closeGroup(results_addGroup(group_base)) - group = trim(group_base)//'/generic' - call results_closeGroup(results_addGroup(group)) - !temp = reshape(homogenization_F,[3,3,discretization_nIPs*discretization_Nelems]) - !call results_writeDataset(group,temp,'F',& - ! 'deformation gradient','1') - !temp = reshape(homogenization_P,[3,3,discretization_nIPs*discretization_Nelems]) - !call results_writeDataset(group,temp,'P',& - ! '1st Piola-Kirchhoff stress','Pa') - - group = trim(group_base)//'/mech' - call results_closeGroup(results_addGroup(group)) - select case(material_homogenization_type(p)) - case(HOMOGENIZATION_rgc_ID) - call mech_RGC_results(homogenization_typeInstance(p),group) - end select + call mech_results(group_base,ho) group = trim(group_base)//'/damage' call results_closeGroup(results_addGroup(group)) - select case(damage_type(p)) - case(DAMAGE_LOCAL_ID) - call damage_local_results(p,group) + select case(damage_type(ho)) case(DAMAGE_NONLOCAL_ID) - call damage_nonlocal_results(p,group) + call damage_nonlocal_results(ho,group) end select group = trim(group_base)//'/thermal' call results_closeGroup(results_addGroup(group)) - select case(thermal_type(p)) - case(THERMAL_ADIABATIC_ID) - call thermal_adiabatic_results(p,group) + select case(thermal_type(ho)) case(THERMAL_CONDUCTION_ID) - call thermal_conduction_results(p,group) + call thermal_conduction_results(ho,group) end select enddo end subroutine homogenization_results + +!-------------------------------------------------------------------------------------------------- +!> @brief Forward data after successful increment. +! ToDo: Any guessing for the current states possible? +!-------------------------------------------------------------------------------------------------- +subroutine homogenization_forward + + integer :: ho + + + do ho = 1, size(material_name_homogenization) + homogState (ho)%state0 = homogState (ho)%state + damageState(ho)%state0 = damageState(ho)%state + enddo + +end subroutine homogenization_forward + end module homogenization diff --git a/src/homogenization_mech.f90 b/src/homogenization_mech.f90 new file mode 100644 index 000000000..641e960fd --- /dev/null +++ b/src/homogenization_mech.f90 @@ -0,0 +1,255 @@ +!-------------------------------------------------------------------------------------------------- +!> @author Martin Diehl, KU Leuven +!> @brief Partition F and homogenize P/dPdF +!-------------------------------------------------------------------------------------------------- +submodule(homogenization) homogenization_mech + + + interface + + module subroutine mech_none_init + end subroutine mech_none_init + + module subroutine mech_isostrain_init + end subroutine mech_isostrain_init + + module subroutine mech_RGC_init(num_homogMech) + class(tNode), pointer, intent(in) :: & + num_homogMech !< pointer to mechanical homogenization numerics data + end subroutine mech_RGC_init + + + module subroutine mech_isostrain_partitionDeformation(F,avgF) + real(pReal), dimension (:,:,:), intent(out) :: F !< partitioned deformation gradient + real(pReal), dimension (3,3), intent(in) :: avgF !< average deformation gradient at material point + end subroutine mech_isostrain_partitionDeformation + + module subroutine mech_RGC_partitionDeformation(F,avgF,instance,of) + real(pReal), dimension (:,:,:), intent(out) :: F !< partitioned deformation gradient + real(pReal), dimension (3,3), intent(in) :: avgF !< average deformation gradient at material point + integer, intent(in) :: & + instance, & + of + end subroutine mech_RGC_partitionDeformation + + + module subroutine mech_isostrain_averageStressAndItsTangent(avgP,dAvgPdAvgF,P,dPdF,instance) + real(pReal), dimension (3,3), intent(out) :: avgP !< average stress at material point + real(pReal), dimension (3,3,3,3), intent(out) :: dAvgPdAvgF !< average stiffness at material point + + real(pReal), dimension (:,:,:), intent(in) :: P !< partitioned stresses + real(pReal), dimension (:,:,:,:,:), intent(in) :: dPdF !< partitioned stiffnesses + integer, intent(in) :: instance + end subroutine mech_isostrain_averageStressAndItsTangent + + module subroutine mech_RGC_averageStressAndItsTangent(avgP,dAvgPdAvgF,P,dPdF,instance) + real(pReal), dimension (3,3), intent(out) :: avgP !< average stress at material point + real(pReal), dimension (3,3,3,3), intent(out) :: dAvgPdAvgF !< average stiffness at material point + + real(pReal), dimension (:,:,:), intent(in) :: P !< partitioned stresses + real(pReal), dimension (:,:,:,:,:), intent(in) :: dPdF !< partitioned stiffnesses + integer, intent(in) :: instance + end subroutine mech_RGC_averageStressAndItsTangent + + + module function mech_RGC_updateState(P,F,F0,avgF,dt,dPdF,ip,el) result(doneAndHappy) + logical, dimension(2) :: doneAndHappy + real(pReal), dimension(:,:,:), intent(in) :: & + P,& !< partitioned stresses + F,& !< partitioned deformation gradients + F0 !< partitioned initial deformation gradients + real(pReal), dimension(:,:,:,:,:), intent(in) :: dPdF !< partitioned stiffnesses + real(pReal), dimension(3,3), intent(in) :: avgF !< average F + real(pReal), intent(in) :: dt !< time increment + integer, intent(in) :: & + ip, & !< integration point number + el !< element number + end function mech_RGC_updateState + + + module subroutine mech_RGC_results(instance,group) + integer, intent(in) :: instance !< homogenization instance + character(len=*), intent(in) :: group !< group name in HDF5 file + end subroutine mech_RGC_results + + end interface + +contains + +!-------------------------------------------------------------------------------------------------- +!> @brief Allocate variables and set parameters. +!-------------------------------------------------------------------------------------------------- +module subroutine mech_init(num_homog) + + class(tNode), pointer, intent(in) :: & + num_homog + + class(tNode), pointer :: & + num_homogMech + + print'(/,a)', ' <<<+- homogenization_mech init -+>>>' + + allocate(homogenization_dPdF(3,3,3,3,discretization_nIPs*discretization_Nelems), source=0.0_pReal) + homogenization_F0 = spread(math_I3,3,discretization_nIPs*discretization_Nelems) ! initialize to identity + homogenization_F = homogenization_F0 ! initialize to identity + allocate(homogenization_P(3,3,discretization_nIPs*discretization_Nelems), source=0.0_pReal) + + num_homogMech => num_homog%get('mech',defaultVal=emptyDict) + if (any(homogenization_type == HOMOGENIZATION_NONE_ID)) call mech_none_init + if (any(homogenization_type == HOMOGENIZATION_ISOSTRAIN_ID)) call mech_isostrain_init + if (any(homogenization_type == HOMOGENIZATION_RGC_ID)) call mech_RGC_init(num_homogMech) + +end subroutine mech_init + + +!-------------------------------------------------------------------------------------------------- +!> @brief Partition F onto the individual constituents. +!-------------------------------------------------------------------------------------------------- +module subroutine mech_partition(subF,ip,el) + + real(pReal), intent(in), dimension(3,3) :: & + subF + integer, intent(in) :: & + ip, & !< integration point + el !< element number + + chosenHomogenization: select case(homogenization_type(material_homogenizationAt(el))) + + case (HOMOGENIZATION_NONE_ID) chosenHomogenization + crystallite_F(1:3,1:3,1,ip,el) = subF + + case (HOMOGENIZATION_ISOSTRAIN_ID) chosenHomogenization + call mech_isostrain_partitionDeformation(& + crystallite_F(1:3,1:3,1:homogenization_Nconstituents(material_homogenizationAt(el)),ip,el), & + subF) + + case (HOMOGENIZATION_RGC_ID) chosenHomogenization + call mech_RGC_partitionDeformation(& + crystallite_F(1:3,1:3,1:homogenization_Nconstituents(material_homogenizationAt(el)),ip,el), & + subF,& + ip, & + el) + + end select chosenHomogenization + +end subroutine mech_partition + + +!-------------------------------------------------------------------------------------------------- +!> @brief Average P and dPdF from the individual constituents. +!-------------------------------------------------------------------------------------------------- +module subroutine mech_homogenize(ip,el) + + integer, intent(in) :: & + ip, & !< integration point + el !< element number + integer :: co,ce + real(pReal) :: dPdFs(3,3,3,3,homogenization_Nconstituents(material_homogenizationAt(el))) + + + ce = (el-1)* discretization_nIPs + ip + chosenHomogenization: select case(homogenization_type(material_homogenizationAt(el))) + + case (HOMOGENIZATION_NONE_ID) chosenHomogenization + homogenization_P(1:3,1:3,ce) = crystallite_P(1:3,1:3,1,ip,el) + homogenization_dPdF(1:3,1:3,1:3,1:3,ce) = crystallite_stressTangent(1,ip,el) + + case (HOMOGENIZATION_ISOSTRAIN_ID) chosenHomogenization + do co = 1, homogenization_Nconstituents(material_homogenizationAt(el)) + dPdFs(:,:,:,:,co) = crystallite_stressTangent(co,ip,el) + enddo + call mech_isostrain_averageStressAndItsTangent(& + homogenization_P(1:3,1:3,ce), & + homogenization_dPdF(1:3,1:3,1:3,1:3,ce),& + crystallite_P(1:3,1:3,1:homogenization_Nconstituents(material_homogenizationAt(el)),ip,el), & + dPdFs, & + homogenization_typeInstance(material_homogenizationAt(el))) + + case (HOMOGENIZATION_RGC_ID) chosenHomogenization + do co = 1, homogenization_Nconstituents(material_homogenizationAt(el)) + dPdFs(:,:,:,:,co) = crystallite_stressTangent(co,ip,el) + enddo + call mech_RGC_averageStressAndItsTangent(& + homogenization_P(1:3,1:3,ce), & + homogenization_dPdF(1:3,1:3,1:3,1:3,ce),& + crystallite_P(1:3,1:3,1:homogenization_Nconstituents(material_homogenizationAt(el)),ip,el), & + dPdFs, & + homogenization_typeInstance(material_homogenizationAt(el))) + + end select chosenHomogenization + +end subroutine mech_homogenize + + +!-------------------------------------------------------------------------------------------------- +!> @brief update the internal state of the homogenization scheme and tell whether "done" and +!> "happy" with result +!-------------------------------------------------------------------------------------------------- +module function mech_updateState(subdt,subF,ip,el) result(doneAndHappy) + + real(pReal), intent(in) :: & + subdt !< current time step + real(pReal), intent(in), dimension(3,3) :: & + subF + integer, intent(in) :: & + ip, & !< integration point + el !< element number + logical, dimension(2) :: doneAndHappy + + integer :: co + real(pReal) :: dPdFs(3,3,3,3,homogenization_Nconstituents(material_homogenizationAt(el))) + + + if (homogenization_type(material_homogenizationAt(el)) == HOMOGENIZATION_RGC_ID) then + do co = 1, homogenization_Nconstituents(material_homogenizationAt(el)) + dPdFs(:,:,:,:,co) = crystallite_stressTangent(co,ip,el) + enddo + doneAndHappy = & + mech_RGC_updateState(crystallite_P(1:3,1:3,1:homogenization_Nconstituents(material_homogenizationAt(el)),ip,el), & + crystallite_F(1:3,1:3,1:homogenization_Nconstituents(material_homogenizationAt(el)),ip,el), & + crystallite_partitionedF0(1:3,1:3,1:homogenization_Nconstituents(material_homogenizationAt(el)),ip,el),& + subF,& + subdt, & + dPdFs, & + ip, & + el) + else + doneAndHappy = .true. + endif + +end function mech_updateState + + +!-------------------------------------------------------------------------------------------------- +!> @brief Write results to file. +!-------------------------------------------------------------------------------------------------- +module subroutine mech_results(group_base,h) + use material, only: & + material_homogenization_type => homogenization_type + + character(len=*), intent(in) :: group_base + integer, intent(in) :: h + + character(len=:), allocatable :: group + + group = trim(group_base)//'/mech' + call results_closeGroup(results_addGroup(group)) + + select case(material_homogenization_type(h)) + + case(HOMOGENIZATION_rgc_ID) + call mech_RGC_results(homogenization_typeInstance(h),group) + + end select + + !temp = reshape(homogenization_F,[3,3,discretization_nIPs*discretization_Nelems]) + !call results_writeDataset(group,temp,'F',& + ! 'deformation gradient','1') + !temp = reshape(homogenization_P,[3,3,discretization_nIPs*discretization_Nelems]) + !call results_writeDataset(group,temp,'P',& + ! '1st Piola-Kirchhoff stress','Pa') + +end subroutine mech_results + + +end submodule homogenization_mech diff --git a/src/homogenization_mech_RGC.f90 b/src/homogenization_mech_RGC.f90 index 585752469..04ec73845 100644 --- a/src/homogenization_mech_RGC.f90 +++ b/src/homogenization_mech_RGC.f90 @@ -6,8 +6,9 @@ !> @brief Relaxed grain cluster (RGC) homogenization scheme !> N_constituents is defined as p x q x r (cluster) !-------------------------------------------------------------------------------------------------- -submodule(homogenization) homogenization_mech_RGC +submodule(homogenization:homogenization_mech) homogenization_mech_RGC use rotations + use lattice type :: tParameters integer, dimension(:), allocatable :: & @@ -18,8 +19,6 @@ submodule(homogenization) homogenization_mech_RGC real(pReal), dimension(:), allocatable :: & D_alpha, & a_g - integer :: & - of_debug = 0 character(len=pStringLen), allocatable, dimension(:) :: & output end type tParameters @@ -151,12 +150,6 @@ module subroutine mech_RGC_init(num_homogMech) st0 => state0(homogenization_typeInstance(h)), & dst => dependentState(homogenization_typeInstance(h))) -#ifdef DEBUG - if (h==material_homogenizationAt(debugHomog%element)) then - prm%of_debug = material_homogenizationMemberAt(debugHomog%ip,debugHomog%element) - endif -#endif - #if defined (__GFORTRAN__) prm%output = output_asStrings(homogMech) #else @@ -239,17 +232,6 @@ module subroutine mech_RGC_partitionDeformation(F,avgF,instance,of) F(i,j,iGrain) = F(i,j,iGrain) + aVect(i)*nVect(j) ! calculating deformation relaxations due to interface relaxation enddo F(1:3,1:3,iGrain) = F(1:3,1:3,iGrain) + avgF ! resulting relaxed deformation gradient - -#ifdef DEBUG - if (debugHomog%extensive) then - print'(a,i3)',' Deformation gradient of grain: ',iGrain - do i = 1,3 - print'(1x,3(e15.8,1x))',(F(i,j,iGrain), j = 1,3) - enddo - print*,' ' - flush(IO_STDOUT) - endif -#endif enddo end associate @@ -261,7 +243,18 @@ end subroutine mech_RGC_partitionDeformation !> @brief update the internal state of the homogenization scheme and tell whether "done" and ! "happy" with result !-------------------------------------------------------------------------------------------------- -module procedure mech_RGC_updateState +module function mech_RGC_updateState(P,F,F0,avgF,dt,dPdF,ip,el) result(doneAndHappy) + logical, dimension(2) :: doneAndHappy + real(pReal), dimension(:,:,:), intent(in) :: & + P,& !< partitioned stresses + F,& !< partitioned deformation gradients + F0 !< partitioned initial deformation gradients + real(pReal), dimension(:,:,:,:,:), intent(in) :: dPdF !< partitioned stiffnesses + real(pReal), dimension(3,3), intent(in) :: avgF !< average F + real(pReal), intent(in) :: dt !< time increment + integer, intent(in) :: & + ip, & !< integration point number + el !< element number integer, dimension(4) :: intFaceN,intFaceP,faceID integer, dimension(3) :: nGDim,iGr3N,iGr3P @@ -273,13 +266,9 @@ module procedure mech_RGC_updateState logical :: error real(pReal), dimension(:,:), allocatable :: tract,jmatrix,jnverse,smatrix,pmatrix,rmatrix real(pReal), dimension(:), allocatable :: resid,relax,p_relax,p_resid,drelax -#ifdef DEBUG - integer, dimension(3) :: stresLoc - integer, dimension(2) :: residLoc -#endif zeroTimeStep: if(dEq0(dt)) then - mech_RGC_updateState = .true. ! pretend everything is fine and return + doneAndHappy = .true. ! pretend everything is fine and return return endif zeroTimeStep @@ -303,16 +292,6 @@ module procedure mech_RGC_updateState relax = stt%relaxationVector(:,of) drelax = stt%relaxationVector(:,of) - st0%relaxationVector(:,of) -#ifdef DEBUG - if (debugHomog%extensive) then - print*, 'Obtained state: ' - do i = 1,size(stt%relaxationVector(:,of)) - print'(1x,2(e15.8,1x))', stt%relaxationVector(i,of) - enddo - print*,' ' - endif -#endif - !-------------------------------------------------------------------------------------------------- ! computing interface mismatch and stress penalty tensor for all interfaces of all grains call stressPenalty(R,NN,avgF,F,ip,el,instance,of) @@ -353,13 +332,6 @@ module procedure mech_RGC_updateState enddo enddo -#ifdef DEBUG - if (debugHomog%extensive) then - print'(a,i3)',' Traction at interface: ',iNum - print'(1x,3(e15.8,1x))',(tract(iNum,j), j = 1,3) - print*,' ' - endif -#endif enddo !-------------------------------------------------------------------------------------------------- @@ -367,29 +339,12 @@ module procedure mech_RGC_updateState stresMax = maxval(abs(P)) ! get the maximum of first Piola-Kirchhoff (material) stress residMax = maxval(abs(tract)) ! get the maximum of the residual -#ifdef DEBUG - if (debugHomog%extensive .and. prm%of_debug == of) then - stresLoc = maxloc(abs(P)) - residLoc = maxloc(abs(tract)) - print'(a,i2,1x,i4)',' RGC residual check ... ',ip,el - print'(a,e15.8,a,i3,a,i2,i2)', ' Max stress: ',stresMax, & - '@ grain ',stresLoc(3),' in component ',stresLoc(1),stresLoc(2) - print'(a,e15.8,a,i3,a,i2)',' Max residual: ',residMax, & - ' @ iface ',residLoc(1),' in direction ',residLoc(2) - flush(IO_STDOUT) - endif -#endif - - mech_RGC_updateState = .false. + doneAndHappy = .false. !-------------------------------------------------------------------------------------------------- ! If convergence reached => done and happy if (residMax < num%rtol*stresMax .or. residMax < num%atol) then - mech_RGC_updateState = .true. -#ifdef DEBUG - if (debugHomog%extensive .and. prm%of_debug == of) & - print*, '... done and happy'; flush(IO_STDOUT) -#endif + doneAndHappy = .true. !-------------------------------------------------------------------------------------------------- ! compute/update the state for postResult, i.e., all energy densities computed by time-integration @@ -406,41 +361,14 @@ module procedure mech_RGC_updateState dst%relaxationRate_avg(of) = sum(abs(drelax))/dt/real(3*nIntFaceTot,pReal) dst%relaxationRate_max(of) = maxval(abs(drelax))/dt -#ifdef DEBUG - if (debugHomog%extensive .and. prm%of_debug == of) then - print'(a,e15.8)', ' Constitutive work: ',stt%work(of) - print'(a,3(1x,e15.8))', ' Magnitude mismatch: ',dst%mismatch(1,of), & - dst%mismatch(2,of), & - dst%mismatch(3,of) - print'(a,e15.8)', ' Penalty energy: ', stt%penaltyEnergy(of) - print'(a,e15.8,/)', ' Volume discrepancy: ', dst%volumeDiscrepancy(of) - print'(a,e15.8)', ' Maximum relaxation rate: ', dst%relaxationRate_max(of) - print'(a,e15.8,/)', ' Average relaxation rate: ', dst%relaxationRate_avg(of) - flush(IO_STDOUT) - endif -#endif - return !-------------------------------------------------------------------------------------------------- ! if residual blows-up => done but unhappy elseif (residMax > num%relMax*stresMax .or. residMax > num%absMax) then ! try to restart when residual blows up exceeding maximum bound - mech_RGC_updateState = [.true.,.false.] ! with direct cut-back - -#ifdef DEBUG - if (debugHomog%extensive .and. prm%of_debug == of) & - print'(a,/)', ' ... broken'; flush(IO_STDOUT) -#endif - + doneAndHappy = [.true.,.false.] ! with direct cut-back return - - else ! proceed with computing the Jacobian and state update -#ifdef DEBUG - if (debugHomog%extensive .and. prm%of_debug == of) & - print'(a,/)', ' ... not yet done'; flush(IO_STDOUT) -#endif - - endif + endif !--------------------------------------------------------------------------------------------------- ! construct the global Jacobian matrix for updating the global relaxation vector array when @@ -492,17 +420,6 @@ module procedure mech_RGC_updateState enddo enddo -#ifdef DEBUG - if (debugHomog%extensive) then - print*, 'Jacobian matrix of stress' - do i = 1,3*nIntFaceTot - print'(1x,100(e11.4,1x))',(smatrix(i,j), j = 1,3*nIntFaceTot) - enddo - print*,' ' - flush(IO_STDOUT) - endif -#endif - !-------------------------------------------------------------------------------------------------- ! ... of the stress penalty tangent (mismatch penalty and volume penalty, computed using numerical ! perturbation method) "pmatrix" @@ -552,16 +469,6 @@ module procedure mech_RGC_updateState pmatrix(:,ipert) = p_resid/num%pPert enddo -#ifdef DEBUG - if (debugHomog%extensive) then - print*, 'Jacobian matrix of penalty' - do i = 1,3*nIntFaceTot - print'(1x,100(e11.4,1x))',(pmatrix(i,j), j = 1,3*nIntFaceTot) - enddo - print*,' ' - flush(IO_STDOUT) - endif -#endif !-------------------------------------------------------------------------------------------------- ! ... of the numerical viscosity traction "rmatrix" @@ -571,48 +478,16 @@ module procedure mech_RGC_updateState (abs(drelax(i))/(num%refRelaxRate*dt))**(num%viscPower - 1.0_pReal) ! only in the main diagonal term enddo -#ifdef DEBUG - if (debugHomog%extensive) then - print*, 'Jacobian matrix of penalty' - do i = 1,3*nIntFaceTot - print'(1x,100(e11.4,1x))',(rmatrix(i,j), j = 1,3*nIntFaceTot) - enddo - print*,' ' - flush(IO_STDOUT) - endif -#endif !-------------------------------------------------------------------------------------------------- ! The overall Jacobian matrix summarizing contributions of smatrix, pmatrix, rmatrix allocate(jmatrix(3*nIntFaceTot,3*nIntFaceTot)); jmatrix = smatrix + pmatrix + rmatrix -#ifdef DEBUG - if (debugHomog%extensive) then - print*, 'Jacobian matrix (total)' - do i = 1,3*nIntFaceTot - print'(1x,100(e11.4,1x))',(jmatrix(i,j), j = 1,3*nIntFaceTot) - enddo - print*,' ' - flush(IO_STDOUT) - endif -#endif - !-------------------------------------------------------------------------------------------------- ! computing the update of the state variable (relaxation vectors) using the Jacobian matrix allocate(jnverse(3*nIntFaceTot,3*nIntFaceTot),source=0.0_pReal) call math_invert(jnverse,error,jmatrix) -#ifdef DEBUG - if (debugHomog%extensive) then - print*, 'Jacobian inverse' - do i = 1,3*nIntFaceTot - print'(1x,100(e11.4,1x))',(jnverse(i,j), j = 1,3*nIntFaceTot) - enddo - print*,' ' - flush(IO_STDOUT) - endif -#endif - !-------------------------------------------------------------------------------------------------- ! calculate the state update (global relaxation vectors) for the next Newton-Raphson iteration drelax = 0.0_pReal @@ -621,7 +496,7 @@ module procedure mech_RGC_updateState enddo; enddo stt%relaxationVector(:,of) = relax + drelax ! Updateing the state variable for the next iteration if (any(abs(drelax) > num%maxdRelax)) then ! Forcing cutback when the incremental change of relaxation vector becomes too large - mech_RGC_updateState = [.true.,.false.] + doneAndHappy = [.true.,.false.] !$OMP CRITICAL (write2out) print'(a,i3,a,i3,a)',' RGC_updateState: ip ',ip,' | el ',el,' enforces cutback' print'(a,e15.8)',' due to large relaxation change = ',maxval(abs(drelax)) @@ -629,17 +504,6 @@ module procedure mech_RGC_updateState !$OMP END CRITICAL (write2out) endif -#ifdef DEBUG - if (debugHomog%extensive) then - print*, 'Returned state: ' - do i = 1,size(stt%relaxationVector(:,of)) - print'(1x,2(e15.8,1x))', stt%relaxationVector(i,of) - enddo - print*,' ' - flush(IO_STDOUT) - endif -#endif - end associate contains @@ -661,8 +525,10 @@ module procedure mech_RGC_updateState real(pReal), dimension (3) :: nVect,surfCorr real(pReal), dimension (2) :: Gmoduli integer :: iGrain,iGNghb,iFace,i,j,k,l - real(pReal) :: muGrain,muGNghb,nDefNorm,bgGrain,bgGNghb - real(pReal), parameter :: nDefToler = 1.0e-10_pReal + real(pReal) :: muGrain,muGNghb,nDefNorm + real(pReal), parameter :: & + nDefToler = 1.0e-10_pReal, & + b = 2.5e-10_pReal ! Length of Burgers vector nGDim = param(instance)%N_constituents rPen = 0.0_pReal @@ -676,19 +542,11 @@ module procedure mech_RGC_updateState associate(prm => param(instance)) -#ifdef DEBUG - if (debugHomog%extensive .and. prm%of_debug == of) then - print'(a,2(1x,i3))', ' Correction factor: ',ip,el - print*, surfCorr - endif -#endif !----------------------------------------------------------------------------------------------- ! computing the mismatch and penalty stress tensor of all grains grainLoop: do iGrain = 1,product(prm%N_constituents) - Gmoduli = equivalentModuli(iGrain,ip,el) - muGrain = Gmoduli(1) ! collecting the equivalent shear modulus of grain - bgGrain = Gmoduli(2) ! and the lengthh of Burgers vector + muGrain = equivalentMu(iGrain,ip,el) iGrain3 = grain1to3(iGrain,prm%N_constituents) ! get the grain ID in local 3-dimensional index (x,y,z)-position interfaceLoop: do iFace = 1,6 @@ -700,9 +558,7 @@ module procedure mech_RGC_updateState where(iGNghb3 < 1) iGNghb3 = nGDim where(iGNghb3 >nGDim) iGNghb3 = 1 iGNghb = grain3to1(iGNghb3,prm%N_constituents) ! get the ID of the neighboring grain - Gmoduli = equivalentModuli(iGNghb,ip,el) ! collect the shear modulus and Burgers vector of the neighbor - muGNghb = Gmoduli(1) - bgGNghb = Gmoduli(2) + muGNghb = equivalentMu(iGNghb,ip,el) gDef = 0.5_pReal*(fDef(1:3,1:3,iGNghb) - fDef(1:3,1:3,iGrain)) ! difference/jump in deformation gradeint across the neighbor !------------------------------------------------------------------------------------------- @@ -717,30 +573,19 @@ module procedure mech_RGC_updateState enddo; enddo nDefNorm = max(nDefToler,sqrt(nDefNorm)) ! approximation to zero mismatch if mismatch is zero (singularity) nMis(abs(intFace(1)),iGrain) = nMis(abs(intFace(1)),iGrain) + nDefNorm ! total amount of mismatch experienced by the grain (at all six interfaces) -#ifdef DEBUG - if (debugHomog%extensive .and. prm%of_debug == of) then - print'(a,i2,a,i3)',' Mismatch to face: ',intFace(1),' neighbor grain: ',iGNghb - print*, transpose(nDef) - print'(a,e11.4)', ' with magnitude: ',nDefNorm - endif -#endif + !------------------------------------------------------------------------------------------- ! compute the stress penalty of all interfaces do i = 1,3; do j = 1,3; do k = 1,3; do l = 1,3 - rPen(i,j,iGrain) = rPen(i,j,iGrain) + 0.5_pReal*(muGrain*bgGrain + muGNghb*bgGNghb)*prm%xi_alpha & + rPen(i,j,iGrain) = rPen(i,j,iGrain) + 0.5_pReal*(muGrain*b + muGNghb*b)*prm%xi_alpha & *surfCorr(abs(intFace(1)))/prm%D_alpha(abs(intFace(1))) & *cosh(prm%c_alpha*nDefNorm) & *0.5_pReal*nVect(l)*nDef(i,k)/nDefNorm*math_LeviCivita(k,l,j) & *tanh(nDefNorm/num%xSmoo) enddo; enddo;enddo; enddo enddo interfaceLoop -#ifdef DEBUG - if (debugHomog%extensive .and. prm%of_debug == of) then - print'(a,i2)', ' Penalty of grain: ',iGrain - print*, transpose(rPen(1:3,1:3,iGrain)) - endif -#endif + enddo grainLoop @@ -783,13 +628,6 @@ module procedure mech_RGC_updateState vPen(:,:,i) = -1.0_pReal/real(nGrain,pReal)*num%volDiscrMod*num%volDiscrPow/num%maxVolDiscr* & sign((abs(vDiscrep)/num%maxVolDiscr)**(num%volDiscrPow - 1.0),vDiscrep)* & gVol(i)*transpose(math_inv33(fDef(:,:,i))) - -#ifdef DEBUG - if (debugHomog%extensive .and. param(instance)%of_debug == of) then - print'(a,i2)',' Volume penalty of grain: ',i - print*, transpose(vPen(:,:,i)) - endif -#endif enddo end subroutine volumePenalty @@ -827,44 +665,26 @@ module procedure mech_RGC_updateState end function surfaceCorrection - !-------------------------------------------------------------------------------------------------- + !------------------------------------------------------------------------------------------------- !> @brief compute the equivalent shear and bulk moduli from the elasticity tensor - !-------------------------------------------------------------------------------------------------- - function equivalentModuli(grainID,ip,el) - - real(pReal), dimension(2) :: equivalentModuli + !------------------------------------------------------------------------------------------------- + real(pReal) function equivalentMu(grainID,ip,el) integer, intent(in) :: & grainID,& ip, & !< integration point number el !< element number - real(pReal), dimension(6,6) :: elasTens - real(pReal) :: & - cEquiv_11, & - cEquiv_12, & - cEquiv_44 - - elasTens = constitutive_homogenizedC(grainID,ip,el) - - !---------------------------------------------------------------------------------------------- - ! compute the equivalent shear modulus after Turterltaub and Suiker, JMPS (2005) - cEquiv_11 = (elasTens(1,1) + elasTens(2,2) + elasTens(3,3))/3.0_pReal - cEquiv_12 = (elasTens(1,2) + elasTens(2,3) + elasTens(3,1) + & - elasTens(1,3) + elasTens(2,1) + elasTens(3,2))/6.0_pReal - cEquiv_44 = (elasTens(4,4) + elasTens(5,5) + elasTens(6,6))/3.0_pReal - equivalentModuli(1) = 0.2_pReal*(cEquiv_11 - cEquiv_12) + 0.6_pReal*cEquiv_44 - - !---------------------------------------------------------------------------------------------- - ! obtain the length of Burgers vector (could be model dependend) - equivalentModuli(2) = 2.5e-10_pReal - - end function equivalentModuli - !-------------------------------------------------------------------------------------------------- + equivalentMu = lattice_equivalent_mu(constitutive_homogenizedC(grainID,ip,el),'voigt') + + end function equivalentMu + + + !------------------------------------------------------------------------------------------------- !> @brief calculating the grain deformation gradient (the same with ! homogenization_RGC_partitionDeformation, but used only for perturbation scheme) - !-------------------------------------------------------------------------------------------------- + !------------------------------------------------------------------------------------------------- subroutine grainDeformation(F, avgF, instance, of) real(pReal), dimension(:,:,:), intent(out) :: F !< partitioned F per grain @@ -879,7 +699,7 @@ module procedure mech_RGC_updateState integer, dimension(3) :: iGrain3 integer :: iGrain,iFace,i,j - !------------------------------------------------------------------------------------------------- + !----------------------------------------------------------------------------------------------- ! compute the deformation gradient of individual grains due to relaxations associate(prm => param(instance)) @@ -901,7 +721,7 @@ module procedure mech_RGC_updateState end subroutine grainDeformation -end procedure mech_RGC_updateState +end function mech_RGC_updateState !-------------------------------------------------------------------------------------------------- diff --git a/src/homogenization_mech_isostrain.f90 b/src/homogenization_mech_isostrain.f90 index 751518e09..a56104647 100644 --- a/src/homogenization_mech_isostrain.f90 +++ b/src/homogenization_mech_isostrain.f90 @@ -4,7 +4,7 @@ !> @author Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH !> @brief Isostrain (full constraint Taylor assuption) homogenization scheme !-------------------------------------------------------------------------------------------------- -submodule(homogenization) homogenization_mech_isostrain +submodule(homogenization:homogenization_mech) homogenization_mech_isostrain enum, bind(c); enumerator :: & parallel_ID, & diff --git a/src/homogenization_mech_none.f90 b/src/homogenization_mech_none.f90 index 5b12247cd..d434d1ca0 100644 --- a/src/homogenization_mech_none.f90 +++ b/src/homogenization_mech_none.f90 @@ -4,7 +4,7 @@ !> @author Martin Diehl, Max-Planck-Institut für Eisenforschung GmbH !> @brief dummy homogenization homogenization scheme for 1 constituent per material point !-------------------------------------------------------------------------------------------------- -submodule(homogenization) homogenization_mech_none +submodule(homogenization:homogenization_mech) homogenization_mech_none contains @@ -28,7 +28,7 @@ module subroutine mech_none_init if(homogenization_Nconstituents(h) /= 1) & call IO_error(211,ext_msg='N_constituents (mech_none)') - + Nmaterialpoints = count(material_homogenizationAt == h) homogState(h)%sizeState = 0 allocate(homogState(h)%state0 (0,Nmaterialpoints)) diff --git a/src/kinematics_cleavage_opening.f90 b/src/kinematics_cleavage_opening.f90 index 66bce6a92..a29a290f8 100644 --- a/src/kinematics_cleavage_opening.f90 +++ b/src/kinematics_cleavage_opening.f90 @@ -99,10 +99,10 @@ end function kinematics_cleavage_opening_init !-------------------------------------------------------------------------------------------------- !> @brief contains the constitutive equation for calculating the velocity gradient !-------------------------------------------------------------------------------------------------- -module subroutine kinematics_cleavage_opening_LiAndItsTangent(Ld, dLd_dTstar, S, ipc, ip, el) +module subroutine kinematics_cleavage_opening_LiAndItsTangent(Ld, dLd_dTstar, S, co, ip, el) integer, intent(in) :: & - ipc, & !< grain number + co, & !< grain number ip, & !< integration point number el !< element number real(pReal), intent(in), dimension(3,3) :: & @@ -120,11 +120,11 @@ module subroutine kinematics_cleavage_opening_LiAndItsTangent(Ld, dLd_dTstar, S, udotd, dudotd_dt, udott, dudott_dt, udotn, dudotn_dt homog = material_homogenizationAt(el) - damageOffset = damageMapping(homog)%p(ip,el) + damageOffset = material_homogenizationMemberAt(ip,el) Ld = 0.0_pReal dLd_dTstar = 0.0_pReal - associate(prm => param(kinematics_cleavage_opening_instance(material_phaseAt(ipc,el)))) + associate(prm => param(kinematics_cleavage_opening_instance(material_phaseAt(co,el)))) do i = 1,prm%sum_N_cl traction_crit = prm%g_crit(i)* damage(homog)%p(damageOffset)**2.0_pReal diff --git a/src/kinematics_slipplane_opening.f90 b/src/kinematics_slipplane_opening.f90 index aa0bdfbde..84edab122 100644 --- a/src/kinematics_slipplane_opening.f90 +++ b/src/kinematics_slipplane_opening.f90 @@ -117,10 +117,10 @@ end function kinematics_slipplane_opening_init !-------------------------------------------------------------------------------------------------- !> @brief contains the constitutive equation for calculating the velocity gradient !-------------------------------------------------------------------------------------------------- -module subroutine kinematics_slipplane_opening_LiAndItsTangent(Ld, dLd_dTstar, S, ipc, ip, el) +module subroutine kinematics_slipplane_opening_LiAndItsTangent(Ld, dLd_dTstar, S, co, ip, el) integer, intent(in) :: & - ipc, & !< grain number + co, & !< grain number ip, & !< integration point number el !< element number real(pReal), intent(in), dimension(3,3) :: & @@ -138,10 +138,10 @@ module subroutine kinematics_slipplane_opening_LiAndItsTangent(Ld, dLd_dTstar, S traction_d, traction_t, traction_n, traction_crit, & udotd, dudotd_dt, udott, dudott_dt, udotn, dudotn_dt - phase = material_phaseAt(ipc,el) + phase = material_phaseAt(co,el) instance = kinematics_slipplane_opening_instance(phase) homog = material_homogenizationAt(el) - damageOffset = damageMapping(homog)%p(ip,el) + damageOffset = material_homogenizationMemberAt(ip,el) associate(prm => param(instance)) Ld = 0.0_pReal diff --git a/src/kinematics_thermal_expansion.f90 b/src/kinematics_thermal_expansion.f90 index 2b8b04d85..6d4a39632 100644 --- a/src/kinematics_thermal_expansion.f90 +++ b/src/kinematics_thermal_expansion.f90 @@ -26,7 +26,7 @@ contains !-------------------------------------------------------------------------------------------------- module function kinematics_thermal_expansion_init(kinematics_length) result(myKinematics) - integer, intent(in) :: kinematics_length + integer, intent(in) :: kinematics_length logical, dimension(:,:), allocatable :: myKinematics integer :: Ninstances,p,i,k @@ -35,8 +35,8 @@ module function kinematics_thermal_expansion_init(kinematics_length) result(myKi phases, & phase, & kinematics, & - kinematic_type - + kinematic_type + print'(/,a)', ' <<<+- kinematics_thermal_expansion init -+>>>' myKinematics = kinematics_active('thermal_expansion',kinematics_length) @@ -50,13 +50,13 @@ module function kinematics_thermal_expansion_init(kinematics_length) result(myKi do p = 1, phases%length if(any(myKinematics(:,p))) kinematics_thermal_expansion_instance(p) = count(myKinematics(:,1:p)) - phase => phases%get(p) + phase => phases%get(p) if(count(myKinematics(:,p)) == 0) cycle kinematics => phase%get('kinematics') do k = 1, kinematics%length if(myKinematics(k,p)) then associate(prm => param(kinematics_thermal_expansion_instance(p))) - kinematic_type => kinematics%get(k) + kinematic_type => kinematics%get(k) prm%T_ref = kinematic_type%get_asFloat('T_ref', defaultVal=0.0_pReal) @@ -81,36 +81,13 @@ module function kinematics_thermal_expansion_init(kinematics_length) result(myKi end function kinematics_thermal_expansion_init -!-------------------------------------------------------------------------------------------------- -!> @brief report initial thermal strain based on current temperature deviation from reference -!-------------------------------------------------------------------------------------------------- -pure module function kinematics_thermal_expansion_initialStrain(homog,phase,offset) result(initialStrain) - - integer, intent(in) :: & - phase, & - homog, & - offset - - real(pReal), dimension(3,3) :: & - initialStrain !< initial thermal strain (should be small strain, though) - - associate(prm => param(kinematics_thermal_expansion_instance(phase))) - initialStrain = & - (temperature(homog)%p(offset) - prm%T_ref)**1 / 1. * prm%A(1:3,1:3,1) + & ! constant coefficient - (temperature(homog)%p(offset) - prm%T_ref)**2 / 2. * prm%A(1:3,1:3,2) + & ! linear coefficient - (temperature(homog)%p(offset) - prm%T_ref)**3 / 3. * prm%A(1:3,1:3,3) ! quadratic coefficient - end associate - -end function kinematics_thermal_expansion_initialStrain - - !-------------------------------------------------------------------------------------------------- !> @brief constitutive equation for calculating the velocity gradient !-------------------------------------------------------------------------------------------------- -module subroutine kinematics_thermal_expansion_LiAndItsTangent(Li, dLi_dTstar, ipc, ip, el) +module subroutine kinematics_thermal_expansion_LiAndItsTangent(Li, dLi_dTstar, co, ip, el) integer, intent(in) :: & - ipc, & !< grain number + co, & !< grain number ip, & !< integration point number el !< element number real(pReal), intent(out), dimension(3,3) :: & @@ -124,10 +101,10 @@ module subroutine kinematics_thermal_expansion_LiAndItsTangent(Li, dLi_dTstar, i real(pReal) :: & T, TDot - phase = material_phaseAt(ipc,el) + phase = material_phaseAt(co,el) homog = material_homogenizationAt(el) - T = temperature(homog)%p(thermalMapping(homog)%p(ip,el)) - TDot = temperatureRate(homog)%p(thermalMapping(homog)%p(ip,el)) + T = temperature(homog)%p(material_homogenizationMemberAt(ip,el)) + TDot = temperatureRate(homog)%p(material_homogenizationMemberAt(ip,el)) associate(prm => param(kinematics_thermal_expansion_instance(phase))) Li = TDot * ( & diff --git a/src/lattice.f90 b/src/lattice.f90 index 676232efe..6af135e4e 100644 --- a/src/lattice.f90 +++ b/src/lattice.f90 @@ -421,6 +421,8 @@ module lattice lattice_BCT_ID, & lattice_HEX_ID, & lattice_ORT_ID, & + lattice_equivalent_nu, & + lattice_equivalent_mu, & lattice_applyLatticeSymmetry33, & lattice_SchmidMatrix_slip, & lattice_SchmidMatrix_twin, & @@ -508,8 +510,8 @@ subroutine lattice_init lattice_C66(1:6,1:6,p) = applyLatticeSymmetryC66(lattice_C66(1:6,1:6,p),phase%get_asString('lattice')) - lattice_mu(p) = equivalent_mu(lattice_C66(1:6,1:6,p),'voigt') - lattice_nu(p) = equivalent_nu(lattice_C66(1:6,1:6,p),'voigt') + lattice_nu(p) = lattice_equivalent_nu(lattice_C66(1:6,1:6,p),'voigt') + lattice_mu(p) = lattice_equivalent_mu(lattice_C66(1:6,1:6,p),'voigt') lattice_C66(1:6,1:6,p) = math_sym3333to66(math_Voigt66to3333(lattice_C66(1:6,1:6,p))) ! Literature data is in Voigt notation do i = 1, 6 @@ -2188,15 +2190,16 @@ end function getlabels !> @brief Equivalent Poisson's ratio (ν) !> @details https://doi.org/10.1143/JPSJ.20.635 !-------------------------------------------------------------------------------------------------- -function equivalent_nu(C,assumption) result(nu) +function lattice_equivalent_nu(C,assumption) result(nu) real(pReal), dimension(6,6), intent(in) :: C !< Stiffness tensor (Voigt notation) character(len=*), intent(in) :: assumption !< Assumption ('Voigt' = isostrain, 'Reuss' = isostress) - real(pReal) :: K, mu, nu + logical :: error real(pReal), dimension(6,6) :: S + if (IO_lc(assumption) == 'voigt') then K = (C(1,1)+C(2,2)+C(3,3) +2.0_pReal*(C(1,2)+C(2,3)+C(1,3))) & / 9.0_pReal @@ -2210,25 +2213,26 @@ function equivalent_nu(C,assumption) result(nu) K = 0.0_pReal endif - mu = equivalent_mu(C,assumption) + mu = lattice_equivalent_mu(C,assumption) nu = (1.5_pReal*K -mu)/(3.0_pReal*K+mu) -end function equivalent_nu +end function lattice_equivalent_nu !-------------------------------------------------------------------------------------------------- !> @brief Equivalent shear modulus (μ) !> @details https://doi.org/10.1143/JPSJ.20.635 !-------------------------------------------------------------------------------------------------- -function equivalent_mu(C,assumption) result(mu) +function lattice_equivalent_mu(C,assumption) result(mu) real(pReal), dimension(6,6), intent(in) :: C !< Stiffness tensor (Voigt notation) character(len=*), intent(in) :: assumption !< Assumption ('Voigt' = isostrain, 'Reuss' = isostress) - real(pReal) :: mu + logical :: error real(pReal), dimension(6,6) :: S + if (IO_lc(assumption) == 'voigt') then mu = (1.0_pReal*(C(1,1)+C(2,2)+C(3,3)) -1.0_pReal*(C(1,2)+C(2,3)+C(1,3)) +3.0_pReal*(C(4,4)+C(5,5)+C(6,6))) & / 15.0_pReal @@ -2242,7 +2246,7 @@ function equivalent_mu(C,assumption) result(mu) mu = 0.0_pReal endif -end function equivalent_mu +end function lattice_equivalent_mu !-------------------------------------------------------------------------------------------------- @@ -2266,14 +2270,14 @@ subroutine selfTest call random_number(C) C(1,1) = C(1,1) + 1.0_pReal C = applyLatticeSymmetryC66(C,'aP') - if(dNeq(C(6,6),equivalent_mu(C,'voigt'),1.0e-12_pReal)) error stop 'equivalent_mu/voigt' - if(dNeq(C(6,6),equivalent_mu(C,'voigt'),1.0e-12_pReal)) error stop 'equivalent_mu/reuss' + if(dNeq(C(6,6),lattice_equivalent_mu(C,'voigt'),1.0e-12_pReal)) error stop 'equivalent_mu/voigt' + if(dNeq(C(6,6),lattice_equivalent_mu(C,'voigt'),1.0e-12_pReal)) error stop 'equivalent_mu/reuss' lambda = C(1,2) - if(dNeq(lambda*0.5_pReal/(lambda+equivalent_mu(C,'voigt')),equivalent_nu(C,'voigt'),1.0e-12_pReal)) & - error stop 'equivalent_nu/voigt' - if(dNeq(lambda*0.5_pReal/(lambda+equivalent_mu(C,'reuss')),equivalent_nu(C,'reuss'),1.0e-12_pReal)) & - error stop 'equivalent_nu/reuss' + if(dNeq(lambda*0.5_pReal/(lambda+lattice_equivalent_mu(C,'voigt')), & + lattice_equivalent_nu(C,'voigt'),1.0e-12_pReal)) error stop 'equivalent_nu/voigt' + if(dNeq(lambda*0.5_pReal/(lambda+lattice_equivalent_mu(C,'reuss')), & + lattice_equivalent_nu(C,'reuss'),1.0e-12_pReal)) error stop 'equivalent_nu/reuss' end subroutine selfTest diff --git a/src/marc/discretization_marc.f90 b/src/marc/discretization_marc.f90 index 9696572e5..675e57bd3 100644 --- a/src/marc/discretization_marc.f90 +++ b/src/marc/discretization_marc.f90 @@ -12,7 +12,6 @@ module discretization_marc use DAMASK_interface use IO use config - use FEsolving use element use discretization use geometry_plastic_nonlocal @@ -89,9 +88,6 @@ subroutine discretization_marc_init if (debug_e < 1 .or. debug_e > nElems) call IO_error(602,ext_msg='element') if (debug_i < 1 .or. debug_i > elem%nIPs) call IO_error(602,ext_msg='IP') - FEsolving_execElem = [1,nElems] - FEsolving_execIP = [1,elem%nIPs] - allocate(cellNodeDefinition(elem%nNodes-1)) allocate(connectivity_cell(elem%NcellNodesPerCell,elem%nIPs,nElems)) call buildCells(connectivity_cell,cellNodeDefinition,& @@ -162,7 +158,7 @@ subroutine writeGeometry(elem, & coordinates_temp = coordinates_points call results_writeDataset('geometry',coordinates_temp,'x_p', & - 'initial coordinates of the materialpoints','m') + 'initial coordinates of the materialpoints (cell centers)','m') call results_closeJobFile diff --git a/src/material.f90 b/src/material.f90 index 8679afdc4..581182d22 100644 --- a/src/material.f90 +++ b/src/material.f90 @@ -17,34 +17,9 @@ module material private enum, bind(c); enumerator :: & - ELASTICITY_UNDEFINED_ID, & - ELASTICITY_HOOKE_ID, & - PLASTICITY_UNDEFINED_ID, & - PLASTICITY_NONE_ID, & - PLASTICITY_ISOTROPIC_ID, & - PLASTICITY_PHENOPOWERLAW_ID, & - PLASTICITY_KINEHARDENING_ID, & - PLASTICITY_DISLOTWIN_ID, & - PLASTICITY_DISLOTUNGSTEN_ID, & - PLASTICITY_NONLOCAL_ID, & - SOURCE_UNDEFINED_ID ,& - SOURCE_THERMAL_DISSIPATION_ID, & - SOURCE_THERMAL_EXTERNALHEAT_ID, & - SOURCE_DAMAGE_ISOBRITTLE_ID, & - SOURCE_DAMAGE_ISODUCTILE_ID, & - SOURCE_DAMAGE_ANISOBRITTLE_ID, & - SOURCE_DAMAGE_ANISODUCTILE_ID, & - KINEMATICS_UNDEFINED_ID ,& - KINEMATICS_CLEAVAGE_OPENING_ID, & - KINEMATICS_SLIPPLANE_OPENING_ID, & - KINEMATICS_THERMAL_EXPANSION_ID, & - STIFFNESS_DEGRADATION_UNDEFINED_ID, & - STIFFNESS_DEGRADATION_DAMAGE_ID, & THERMAL_ISOTHERMAL_ID, & - THERMAL_ADIABATIC_ID, & THERMAL_CONDUCTION_ID, & DAMAGE_NONE_ID, & - DAMAGE_LOCAL_ID, & DAMAGE_NONLOCAL_ID, & HOMOGENIZATION_UNDEFINED_ID, & HOMOGENIZATION_NONE_ID, & @@ -52,7 +27,7 @@ module material HOMOGENIZATION_RGC_ID end enum - character(len=pStringLen), public, protected, allocatable, dimension(:) :: & + character(len=:), public, protected, allocatable, dimension(:) :: & material_name_phase, & !< name of each phase material_name_homogenization !< name of each homogenization @@ -64,21 +39,20 @@ module material homogenization_type !< type of each homogenization integer, public, protected :: & - homogenization_maxNconstituents !< max number of grains in any USED homogenization + homogenization_maxNconstituents !< max number of grains in any USED homogenization integer, dimension(:), allocatable, public, protected :: & - homogenization_Nconstituents, & !< number of grains in each homogenization + homogenization_Nconstituents, & !< number of grains in each homogenization homogenization_typeInstance, & !< instance of particular type of each homogenization thermal_typeInstance, & !< instance of particular type of each thermal transport damage_typeInstance !< instance of particular type of each nonlocal damage real(pReal), dimension(:), allocatable, public, protected :: & - thermal_initialT, & !< initial temperature per each homogenization - damage_initialPhi !< initial damage per each homogenization + thermal_initialT !< initial temperature per each homogenization integer, dimension(:), allocatable, public, protected :: & ! (elem) material_homogenizationAt !< homogenization ID of each element - integer, dimension(:,:), allocatable, public, target :: & ! (ip,elem) ToDo: ugly target for mapping hack + integer, dimension(:,:), allocatable, public, protected :: & ! (ip,elem) material_homogenizationMemberAt !< position of the element within its homogenization instance integer, dimension(:,:), allocatable, public, protected :: & ! (constituent,elem) material_phaseAt !< phase ID of each element @@ -87,20 +61,11 @@ module material type(tState), allocatable, dimension(:), public :: & homogState, & - thermalState, & damageState type(Rotation), dimension(:,:,:), allocatable, public, protected :: & material_orientation0 !< initial orientation of each grain,IP,element -! BEGIN DEPRECATED - integer, dimension(:,:), allocatable, private, target :: mappingHomogenizationConst !< mapping from material points to offset in constant state/field -! END DEPRECATED - - type(tHomogMapping), allocatable, dimension(:), public :: & - thermalMapping, & !< mapping for thermal state/fields - damageMapping !< mapping for damage state/fields - type(group_float), allocatable, dimension(:), public :: & temperature, & !< temperature field damage, & !< damage field @@ -108,34 +73,9 @@ module material public :: & material_init, & - ELASTICITY_UNDEFINED_ID, & - ELASTICITY_HOOKE_ID, & - PLASTICITY_UNDEFINED_ID, & - PLASTICITY_NONE_ID, & - PLASTICITY_ISOTROPIC_ID, & - PLASTICITY_PHENOPOWERLAW_ID, & - PLASTICITY_KINEHARDENING_ID, & - PLASTICITY_DISLOTWIN_ID, & - PLASTICITY_DISLOTUNGSTEN_ID, & - PLASTICITY_NONLOCAL_ID, & - SOURCE_UNDEFINED_ID ,& - SOURCE_THERMAL_DISSIPATION_ID, & - SOURCE_THERMAL_EXTERNALHEAT_ID, & - SOURCE_DAMAGE_ISOBRITTLE_ID, & - SOURCE_DAMAGE_ISODUCTILE_ID, & - SOURCE_DAMAGE_ANISOBRITTLE_ID, & - SOURCE_DAMAGE_ANISODUCTILE_ID, & - KINEMATICS_UNDEFINED_ID ,& - KINEMATICS_CLEAVAGE_OPENING_ID, & - KINEMATICS_SLIPPLANE_OPENING_ID, & - KINEMATICS_THERMAL_EXPANSION_ID, & - STIFFNESS_DEGRADATION_UNDEFINED_ID, & - STIFFNESS_DEGRADATION_DAMAGE_ID, & THERMAL_ISOTHERMAL_ID, & - THERMAL_ADIABATIC_ID, & THERMAL_CONDUCTION_ID, & DAMAGE_NONE_ID, & - DAMAGE_LOCAL_ID, & DAMAGE_NONLOCAL_ID, & HOMOGENIZATION_NONE_ID, & HOMOGENIZATION_ISOSTRAIN_ID, & @@ -149,7 +89,6 @@ contains subroutine material_init(restart) logical, intent(in) :: restart - integer :: myHomog print'(/,a)', ' <<<+- material init -+>>>'; flush(IO_STDOUT) @@ -162,39 +101,20 @@ subroutine material_init(restart) allocate(homogState (size(material_name_homogenization))) - allocate(thermalState (size(material_name_homogenization))) allocate(damageState (size(material_name_homogenization))) - allocate(thermalMapping (size(material_name_homogenization))) - allocate(damageMapping (size(material_name_homogenization))) - allocate(temperature (size(material_name_homogenization))) allocate(damage (size(material_name_homogenization))) - allocate(temperatureRate (size(material_name_homogenization))) if (.not. restart) then call results_openJobFile - call results_mapping_constituent(material_phaseAt,material_phaseMemberAt,material_name_phase) + call results_mapping_phase(material_phaseAt,material_phaseMemberAt,material_name_phase) call results_mapping_homogenization(material_homogenizationAt,material_homogenizationMemberAt,material_name_homogenization) call results_closeJobFile endif -!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -! BEGIN DEPRECATED - allocate(mappingHomogenizationConst( discretization_nIPs,discretization_Nelems),source=1) - -! hack needed to initialize field values used during constitutive initialization - do myHomog = 1, size(material_name_homogenization) - thermalMapping (myHomog)%p => mappingHomogenizationConst - damageMapping (myHomog)%p => mappingHomogenizationConst - allocate(temperature (myHomog)%p(1), source=thermal_initialT(myHomog)) - allocate(damage (myHomog)%p(1), source=damage_initialPhi(myHomog)) - allocate(temperatureRate (myHomog)%p(1), source=0.0_pReal) - enddo -! END DEPRECATED - end subroutine material_init @@ -222,7 +142,6 @@ subroutine material_parseHomogenization allocate(thermal_typeInstance(size(material_name_homogenization)), source=0) allocate(damage_typeInstance(size(material_name_homogenization)), source=0) allocate(thermal_initialT(size(material_name_homogenization)), source=300.0_pReal) - allocate(damage_initialPhi(size(material_name_homogenization)), source=1.0_pReal) do h=1, size(material_name_homogenization) homog => material_homogenization%get(h) @@ -247,8 +166,6 @@ subroutine material_parseHomogenization select case (homogThermal%get_asString('type')) case('isothermal') thermal_type(h) = THERMAL_isothermal_ID - case('adiabatic') - thermal_type(h) = THERMAL_adiabatic_ID case('conduction') thermal_type(h) = THERMAL_conduction_ID case default @@ -258,12 +175,9 @@ subroutine material_parseHomogenization if(homog%contains('damage')) then homogDamage => homog%get('damage') - damage_initialPhi(h) = homogDamage%get_asFloat('phi_0',defaultVal=1.0_pReal) select case (homogDamage%get_asString('type')) case('none') damage_type(h) = DAMAGE_none_ID - case('local') - damage_type(h) = DAMAGE_local_ID case('nonlocal') damage_type(h) = DAMAGE_nonlocal_ID case default @@ -392,13 +306,21 @@ end subroutine sanityCheck function getKeys(dict) class(tNode), intent(in) :: dict - character(len=pStringLen), dimension(:), allocatable :: getKeys + character(len=:), dimension(:), allocatable :: getKeys + character(len=pStringLen), dimension(:), allocatable :: temp - integer :: i + integer :: i,l - allocate(getKeys(dict%length)) + allocate(temp(dict%length)) + l = 0 do i=1, dict%length - getKeys(i) = dict%getKey(i) + temp(i) = dict%getKey(i) + l = max(len_trim(temp(i)),l) + enddo + + allocate(character(l)::getKeys(dict%length)) + do i=1, dict%length + getKeys(i) = trim(temp(i)) enddo end function getKeys diff --git a/src/math.f90 b/src/math.f90 index 8005b5406..6b89a9923 100644 --- a/src/math.f90 +++ b/src/math.f90 @@ -279,9 +279,12 @@ real(pReal) pure function math_LeviCivita(i,j,k) integer, intent(in) :: i,j,k - if (all([i,j,k] == [1,2,3]) .or. all([i,j,k] == [2,3,1]) .or. all([i,j,k] == [3,1,2])) then + integer :: o + + + if (any([(all(cshift([i,j,k],o) == [1,2,3]),o=0,2)])) then math_LeviCivita = +1.0_pReal - elseif (all([i,j,k] == [3,2,1]) .or. all([i,j,k] == [2,1,3]) .or. all([i,j,k] == [1,3,2])) then + elseif (any([(all(cshift([i,j,k],o) == [3,2,1]),o=0,2)])) then math_LeviCivita = -1.0_pReal else math_LeviCivita = 0.0_pReal diff --git a/src/mesh/DAMASK_mesh.f90 b/src/mesh/DAMASK_mesh.f90 index 1e353892c..7369520c1 100644 --- a/src/mesh/DAMASK_mesh.f90 +++ b/src/mesh/DAMASK_mesh.f90 @@ -15,7 +15,6 @@ program DAMASK_mesh use IO use math use CPFEM2 - use FEsolving use config use discretization_mesh use FEM_Utilities diff --git a/src/mesh/FEM_utilities.f90 b/src/mesh/FEM_utilities.f90 index 118735e89..2f3633e11 100644 --- a/src/mesh/FEM_utilities.f90 +++ b/src/mesh/FEM_utilities.f90 @@ -160,11 +160,11 @@ subroutine utilities_constitutiveResponse(timeinc,P_av,forwardData) print'(/,a)', ' ... evaluating constitutive response ......................................' - call materialpoint_stressAndItsTangent(timeinc) ! calculate P field + call materialpoint_stressAndItsTangent(timeinc,[1,mesh_maxNips],[1,mesh_NcpElems]) ! calculate P field cutBack = .false. ! reset cutBack status - P_av = sum(sum(homogenization_P,dim=4),dim=3) * wgt ! average of P + P_av = sum(homogenization_P,dim=3) * wgt call MPI_Allreduce(MPI_IN_PLACE,P_av,9,MPI_DOUBLE,MPI_SUM,PETSC_COMM_WORLD,ierr) end subroutine utilities_constitutiveResponse diff --git a/src/mesh/discretization_mesh.f90 b/src/mesh/discretization_mesh.f90 index 0a9c5adaa..67b061fa4 100644 --- a/src/mesh/discretization_mesh.f90 +++ b/src/mesh/discretization_mesh.f90 @@ -18,7 +18,6 @@ module discretization_mesh use config use discretization use results - use FEsolving use FEM_quadrature use YAML_types use prec @@ -30,7 +29,7 @@ module discretization_mesh mesh_Nboundaries, & mesh_NcpElemsGlobal - integer :: & + integer, public, protected :: & mesh_NcpElems !< total number of CP elements in mesh !!!! BEGIN DEPRECATED !!!!! @@ -157,9 +156,6 @@ subroutine discretization_mesh_init(restart) if (debug_element < 1 .or. debug_element > mesh_NcpElems) call IO_error(602,ext_msg='element') if (debug_ip < 1 .or. debug_ip > mesh_maxNips) call IO_error(602,ext_msg='IP') - FEsolving_execElem = [1,mesh_NcpElems] ! parallel loop bounds set to comprise all DAMASK elements - FEsolving_execIP = [1,mesh_maxNips] - allocate(mesh_node0(3,mesh_Nnodes),source=0.0_pReal) call discretization_init(materialAt,& diff --git a/src/mesh/mesh_mech_FEM.f90 b/src/mesh/mesh_mech_FEM.f90 index 8aa084ac8..e19c35998 100644 --- a/src/mesh/mesh_mech_FEM.f90 +++ b/src/mesh/mesh_mech_FEM.f90 @@ -32,7 +32,6 @@ module mesh_mech_FEM type tSolutionParams type(tFieldBC) :: fieldBC real(pReal) :: timeinc - real(pReal) :: timeincOld end type tSolutionParams type(tSolutionParams) :: params @@ -147,14 +146,9 @@ subroutine FEM_mech_init(fieldBC) call PetscFESetQuadrature(mechFE,mechQuad,ierr); CHKERRQ(ierr) call PetscFEGetDimension(mechFE,nBasis,ierr); CHKERRQ(ierr) nBasis = nBasis/nc -#if (PETSC_VERSION_MINOR > 10) call DMAddField(mech_mesh,PETSC_NULL_DMLABEL,mechFE,ierr); CHKERRQ(ierr) call DMCreateDS(mech_mesh,ierr); CHKERRQ(ierr) -#endif call DMGetDS(mech_mesh,mechDS,ierr); CHKERRQ(ierr) -#if (PETSC_VERSION_MINOR < 11) - call PetscDSAddDiscretization(mechDS,mechFE,ierr); CHKERRQ(ierr) -#endif call PetscDSGetTotalDimension(mechDS,cellDof,ierr); CHKERRQ(ierr) call PetscFEDestroy(mechFE,ierr); CHKERRQ(ierr) call PetscQuadratureDestroy(mechQuad,ierr); CHKERRQ(ierr) @@ -163,11 +157,7 @@ subroutine FEM_mech_init(fieldBC) ! Setup FEM mech boundary conditions call DMGetLabel(mech_mesh,'Face Sets',BCLabel,ierr); CHKERRQ(ierr) call DMPlexLabelComplete(mech_mesh,BCLabel,ierr); CHKERRQ(ierr) -#if (PETSC_VERSION_MINOR < 12) - call DMGetSection(mech_mesh,section,ierr); CHKERRQ(ierr) -#else call DMGetLocalSection(mech_mesh,section,ierr); CHKERRQ(ierr) -#endif allocate(pnumComp(1), source=dimPlex) allocate(pnumDof(0:dimPlex), source = 0) do topologDim = 0, dimPlex @@ -205,14 +195,8 @@ subroutine FEM_mech_init(fieldBC) endif endif enddo; enddo -#if (PETSC_VERSION_MINOR < 11) - call DMPlexCreateSection(mech_mesh,dimPlex,1,pNumComp,pNumDof, & - numBC,pBcField,pBcComps,pBcPoints,PETSC_NULL_IS,section,ierr) -#else call DMPlexCreateSection(mech_mesh,nolabel,pNumComp,pNumDof, & numBC,pBcField,pBcComps,pBcPoints,PETSC_NULL_IS,section,ierr) - -#endif CHKERRQ(ierr) call DMSetSection(mech_mesh,section,ierr); CHKERRQ(ierr) do faceSet = 1, numBC @@ -267,11 +251,7 @@ subroutine FEM_mech_init(fieldBC) x_scal(basis+1:basis+dimPlex) = pV0 + matmul(transpose(cellJMat),nodalPointsP + 1.0_pReal) enddo px_scal => x_scal -#if (PETSC_VERSION_MINOR < 11) - call DMPlexVecSetClosure(mech_mesh,section,solution_local,cell,px_scal,INSERT_ALL_VALUES,ierr) -#else - call DMPlexVecSetClosure(mech_mesh,section,solution_local,cell,px_scal,5,ierr) ! PETSc: cbee0a90b60958e5c50c89b1e41f4451dfa6008c -#endif + call DMPlexVecSetClosure(mech_mesh,section,solution_local,cell,px_scal,5,ierr) CHKERRQ(ierr) enddo @@ -302,7 +282,6 @@ type(tSolutionState) function FEM_mech_solution( & !-------------------------------------------------------------------------------------------------- ! set module wide availabe data params%timeinc = timeinc - params%timeincOld = timeinc_old params%fieldBC = fieldBC call SNESSolve(mech_snes,PETSC_NULL_VEC,solution,ierr); CHKERRQ(ierr) ! solve mech_snes based on solution guess (result in solution) @@ -337,16 +316,16 @@ subroutine FEM_mech_formResidual(dm_local,xx_local,f_local,dummy,ierr) Vec :: x_local, f_local, xx_local PetscSection :: section PetscScalar, dimension(:), pointer :: x_scal, pf_scal - PetscScalar, target :: f_scal(cellDof) - PetscReal :: detJ, IcellJMat(dimPlex,dimPlex) - PetscReal, pointer,dimension(:) :: pV0, pCellJ, pInvcellJ, basisField, basisFieldDer + PetscScalar, dimension(cellDof), target :: f_scal + PetscReal :: IcellJMat(dimPlex,dimPlex) + PetscReal, dimension(:),pointer :: pV0, pCellJ, pInvcellJ, basisField, basisFieldDer PetscInt :: cellStart, cellEnd, cell, field, face, & qPt, basis, comp, cidx, & - numFields - PetscReal :: detFAvg - PetscReal :: BMat(dimPlex*dimPlex,cellDof) + numFields, & + bcSize,m + PetscReal :: detFAvg, detJ + PetscReal, dimension(dimPlex*dimPlex,cellDof) :: BMat - PetscInt :: bcSize IS :: bcPoints @@ -355,11 +334,7 @@ subroutine FEM_mech_formResidual(dm_local,xx_local,f_local,dummy,ierr) allocate(pinvcellJ(dimPlex**2)) allocate(x_scal(cellDof)) -#if (PETSC_VERSION_MINOR < 12) - call DMGetSection(dm_local,section,ierr); CHKERRQ(ierr) -#else call DMGetLocalSection(dm_local,section,ierr); CHKERRQ(ierr) -#endif call DMGetDS(dm_local,prob,ierr); CHKERRQ(ierr) call PetscDSGetTabulation(prob,0,basisField,basisFieldDer,ierr) CHKERRQ(ierr) @@ -391,6 +366,7 @@ subroutine FEM_mech_formResidual(dm_local,xx_local,f_local,dummy,ierr) CHKERRQ(ierr) IcellJMat = reshape(pInvcellJ,shape=[dimPlex,dimPlex]) do qPt = 0, nQuadrature-1 + m = cell*nQuadrature + qPt+1 BMat = 0.0 do basis = 0, nBasis-1 do comp = 0, dimPlex-1 @@ -400,15 +376,14 @@ subroutine FEM_mech_formResidual(dm_local,xx_local,f_local,dummy,ierr) (((qPt*nBasis + basis)*dimPlex + comp)*dimPlex+comp+1)*dimPlex)) enddo enddo - homogenization_F(1:dimPlex,1:dimPlex,qPt+1,cell+1) = & - reshape(matmul(BMat,x_scal),shape=[dimPlex,dimPlex], order=[2,1]) + homogenization_F(1:dimPlex,1:dimPlex,m) = reshape(matmul(BMat,x_scal),shape=[dimPlex,dimPlex], order=[2,1]) enddo if (num%BBarStabilisation) then - detFAvg = math_det33(sum(homogenization_F(1:3,1:3,1:nQuadrature,cell+1),dim=3)/real(nQuadrature)) - do qPt = 1, nQuadrature - homogenization_F(1:dimPlex,1:dimPlex,qPt,cell+1) = & - homogenization_F(1:dimPlex,1:dimPlex,qPt,cell+1)* & - (detFAvg/math_det33(homogenization_F(1:3,1:3,qPt,cell+1)))**(1.0/real(dimPlex)) + detFAvg = math_det33(sum(homogenization_F(1:3,1:3,cell*nQuadrature+1:(cell+1)*nQuadrature),dim=3)/real(nQuadrature)) + do qPt = 0, nQuadrature-1 + m = cell*nQuadrature + qPt+1 + homogenization_F(1:dimPlex,1:dimPlex,m) = homogenization_F(1:dimPlex,1:dimPlex,m) & + * (detFAvg/math_det33(homogenization_F(1:3,1:3,m)))**(1.0/real(dimPlex)) enddo endif @@ -432,6 +407,7 @@ subroutine FEM_mech_formResidual(dm_local,xx_local,f_local,dummy,ierr) IcellJMat = reshape(pInvcellJ,shape=[dimPlex,dimPlex]) f_scal = 0.0 do qPt = 0, nQuadrature-1 + m = cell*nQuadrature + qPt+1 BMat = 0.0 do basis = 0, nBasis-1 do comp = 0, dimPlex-1 @@ -443,7 +419,7 @@ subroutine FEM_mech_formResidual(dm_local,xx_local,f_local,dummy,ierr) enddo f_scal = f_scal + & matmul(transpose(BMat), & - reshape(transpose(homogenization_P(1:dimPlex,1:dimPlex,qPt+1,cell+1)), & + reshape(transpose(homogenization_P(1:dimPlex,1:dimPlex,m)), & shape=[dimPlex*dimPlex]))*qWeights(qPt+1) enddo f_scal = f_scal*abs(detJ) @@ -488,7 +464,7 @@ subroutine FEM_mech_formJacobian(dm_local,xx_local,Jac_pre,Jac,dummy,ierr) K_eB PetscInt :: cellStart, cellEnd, cell, field, face, & - qPt, basis, comp, cidx,bcSize + qPt, basis, comp, cidx,bcSize, m IS :: bcPoints @@ -502,11 +478,7 @@ subroutine FEM_mech_formJacobian(dm_local,xx_local,Jac_pre,Jac,dummy,ierr) call MatZeroEntries(Jac,ierr); CHKERRQ(ierr) call DMGetDS(dm_local,prob,ierr); CHKERRQ(ierr) call PetscDSGetTabulation(prob,0,basisField,basisFieldDer,ierr) -#if (PETSC_VERSION_MINOR < 12) - call DMGetSection(dm_local,section,ierr); CHKERRQ(ierr) -#else call DMGetLocalSection(dm_local,section,ierr); CHKERRQ(ierr) -#endif call DMGetGlobalSection(dm_local,gSection,ierr); CHKERRQ(ierr) call DMGetLocalVector(dm_local,x_local,ierr); CHKERRQ(ierr) @@ -535,6 +507,7 @@ subroutine FEM_mech_formJacobian(dm_local,xx_local,Jac_pre,Jac,dummy,ierr) FAvg = 0.0 BMatAvg = 0.0 do qPt = 0, nQuadrature-1 + m = cell*nQuadrature + qPt + 1 BMat = 0.0 do basis = 0, nBasis-1 do comp = 0, dimPlex-1 @@ -545,7 +518,7 @@ subroutine FEM_mech_formJacobian(dm_local,xx_local,Jac_pre,Jac,dummy,ierr) (((qPt*nBasis + basis)*dimPlex + comp)*dimPlex+comp+1)*dimPlex)) enddo enddo - MatA = matmul(reshape(reshape(homogenization_dPdF(1:dimPlex,1:dimPlex,1:dimPlex,1:dimPlex,qPt+1,cell+1), & + MatA = matmul(reshape(reshape(homogenization_dPdF(1:dimPlex,1:dimPlex,1:dimPlex,1:dimPlex,m), & shape=[dimPlex,dimPlex,dimPlex,dimPlex], order=[2,1,4,3]), & shape=[dimPlex*dimPlex,dimPlex*dimPlex]),BMat)*qWeights(qPt+1) if (num%BBarStabilisation) then @@ -553,12 +526,11 @@ subroutine FEM_mech_formJacobian(dm_local,xx_local,Jac_pre,Jac,dummy,ierr) FInv = math_inv33(F) K_eA = K_eA + matmul(transpose(BMat),MatA)*math_det33(FInv)**(1.0/real(dimPlex)) K_eB = K_eB - & - matmul(transpose(matmul(reshape(homogenization_F(1:dimPlex,1:dimPlex,qPt+1,cell+1), & - shape=[dimPlex*dimPlex,1]), & + matmul(transpose(matmul(reshape(homogenization_F(1:dimPlex,1:dimPlex,m),shape=[dimPlex*dimPlex,1]), & matmul(reshape(FInv(1:dimPlex,1:dimPlex), & shape=[1,dimPlex*dimPlex],order=[2,1]),BMat))),MatA) - MatB = MatB + & - matmul(reshape(homogenization_F(1:dimPlex,1:dimPlex,qPt+1,cell+1),shape=[1,dimPlex*dimPlex]),MatA) + MatB = MatB & + + matmul(reshape(homogenization_F(1:dimPlex,1:dimPlex,m),shape=[1,dimPlex*dimPlex]),MatA) FAvg = FAvg + F BMatAvg = BMatAvg + BMat else @@ -686,8 +658,8 @@ subroutine FEM_mech_converged(snes_local,PETScIter,xnorm,snorm,fnorm,reason,dumm print'(/,1x,a,a,i0,a,i0,f0.3)', trim(incInfo), & ' @ Iteration ',PETScIter,' mechanical residual norm = ', & int(fnorm/divTol),fnorm/divTol-int(fnorm/divTol) - write(IO_STDOUT,'(/,a,/,3(3(2x,f12.4,1x)/))',advance='no') ' Piola--Kirchhoff stress / MPa =',& - transpose(P_av)*1.e-6_pReal + print'(/,a,/,2(3(2x,f12.4,1x)/),3(2x,f12.4,1x))', & + ' Piola--Kirchhoff stress / MPa =',transpose(P_av)*1.e-6_pReal flush(IO_STDOUT) end subroutine FEM_mech_converged diff --git a/src/prec.f90 b/src/prec.f90 index 738775e3b..4d73462c4 100644 --- a/src/prec.f90 +++ b/src/prec.f90 @@ -54,7 +54,7 @@ module prec type, extends(tState) :: tPlasticState logical :: & nonlocal = .false. - real(pReal), pointer, dimension(:,:) :: & + real(pReal), pointer, dimension(:,:) :: & slipRate !< slip rate end type @@ -62,10 +62,6 @@ module prec type(tState), dimension(:), allocatable :: p !< tState for each active source mechanism in a phase end type - type :: tHomogMapping - integer, pointer, dimension(:,:) :: p - end type - real(pReal), private, parameter :: PREAL_EPSILON = epsilon(0.0_pReal) !< minimum positive number such that 1.0 + EPSILON /= 1.0. real(pReal), private, parameter :: PREAL_MIN = tiny(0.0_pReal) !< smallest normalized floating point number @@ -112,8 +108,10 @@ logical elemental pure function dEq(a,b,tol) real(pReal), intent(in) :: a,b real(pReal), intent(in), optional :: tol + real(pReal) :: eps + if (present(tol)) then eps = tol else @@ -136,11 +134,8 @@ logical elemental pure function dNeq(a,b,tol) real(pReal), intent(in) :: a,b real(pReal), intent(in), optional :: tol - if (present(tol)) then - dNeq = .not. dEq(a,b,tol) - else - dNeq = .not. dEq(a,b) - endif + + dNeq = .not. dEq(a,b,tol) end function dNeq @@ -155,8 +150,10 @@ logical elemental pure function dEq0(a,tol) real(pReal), intent(in) :: a real(pReal), intent(in), optional :: tol + real(pReal) :: eps + if (present(tol)) then eps = tol else @@ -179,11 +176,8 @@ logical elemental pure function dNeq0(a,tol) real(pReal), intent(in) :: a real(pReal), intent(in), optional :: tol - if (present(tol)) then - dNeq0 = .not. dEq0(a,tol) - else - dNeq0 = .not. dEq0(a) - endif + + dNeq0 = .not. dEq0(a,tol) end function dNeq0 @@ -199,8 +193,10 @@ logical elemental pure function cEq(a,b,tol) complex(pReal), intent(in) :: a,b real(pReal), intent(in), optional :: tol + real(pReal) :: eps + if (present(tol)) then eps = tol else @@ -224,11 +220,8 @@ logical elemental pure function cNeq(a,b,tol) complex(pReal), intent(in) :: a,b real(pReal), intent(in), optional :: tol - if (present(tol)) then - cNeq = .not. cEq(a,b,tol) - else - cNeq = .not. cEq(a,b) - endif + + cNeq = .not. cEq(a,b,tol) end function cNeq @@ -242,6 +235,7 @@ pure function prec_bytesToC_FLOAT(bytes) real(C_FLOAT), dimension(size(bytes,kind=pI64)/(storage_size(0._C_FLOAT,pI64)/8_pI64)) :: & prec_bytesToC_FLOAT + prec_bytesToC_FLOAT = transfer(bytes,prec_bytesToC_FLOAT,size(prec_bytesToC_FLOAT)) end function prec_bytesToC_FLOAT @@ -256,6 +250,7 @@ pure function prec_bytesToC_DOUBLE(bytes) real(C_DOUBLE), dimension(size(bytes,kind=pI64)/(storage_size(0._C_DOUBLE,pI64)/8_pI64)) :: & prec_bytesToC_DOUBLE + prec_bytesToC_DOUBLE = transfer(bytes,prec_bytesToC_DOUBLE,size(prec_bytesToC_DOUBLE)) end function prec_bytesToC_DOUBLE @@ -270,6 +265,7 @@ pure function prec_bytesToC_INT32_T(bytes) integer(C_INT32_T), dimension(size(bytes,kind=pI64)/(storage_size(0_C_INT32_T,pI64)/8_pI64)) :: & prec_bytesToC_INT32_T + prec_bytesToC_INT32_T = transfer(bytes,prec_bytesToC_INT32_T,size(prec_bytesToC_INT32_T)) end function prec_bytesToC_INT32_T @@ -284,6 +280,7 @@ pure function prec_bytesToC_INT64_T(bytes) integer(C_INT64_T), dimension(size(bytes,kind=pI64)/(storage_size(0_C_INT64_T,pI64)/8_pI64)) :: & prec_bytesToC_INT64_T + prec_bytesToC_INT64_T = transfer(bytes,prec_bytesToC_INT64_T,size(prec_bytesToC_INT64_T)) end function prec_bytesToC_INT64_T @@ -299,6 +296,7 @@ subroutine selfTest integer(pInt), dimension(1) :: i real(pReal), dimension(2) :: r + realloc_lhs_test = [1,2] if (any(realloc_lhs_test/=[1,2])) error stop 'LHS allocation' diff --git a/src/quaternions.f90 b/src/quaternions.f90 deleted file mode 100644 index c5c43e3c1..000000000 --- a/src/quaternions.f90 +++ /dev/null @@ -1,534 +0,0 @@ -!--------------------------------------------------------------------------------------------------- -!> @author Martin Diehl, Max-Planck-Institut für Eisenforschung GmbH -!> @author Philip Eisenlohr, Michigan State University -!> @brief general quaternion math, not limited to unit quaternions -!> @details w is the real part, (x, y, z) are the imaginary parts. -!> @details https://en.wikipedia.org/wiki/Quaternion -!--------------------------------------------------------------------------------------------------- -module quaternions - use prec - - implicit none - private - - real(pReal), parameter, public :: P = -1.0_pReal !< parameter for orientation conversion. - - type, public :: quaternion - real(pReal), private :: w = 0.0_pReal - real(pReal), private :: x = 0.0_pReal - real(pReal), private :: y = 0.0_pReal - real(pReal), private :: z = 0.0_pReal - - - contains - procedure, private :: add__ - procedure, private :: pos__ - generic, public :: operator(+) => add__,pos__ - - procedure, private :: sub__ - procedure, private :: neg__ - generic, public :: operator(-) => sub__,neg__ - - procedure, private :: mul_quat__ - procedure, private :: mul_scal__ - generic, public :: operator(*) => mul_quat__, mul_scal__ - - procedure, private :: div_quat__ - procedure, private :: div_scal__ - generic, public :: operator(/) => div_quat__, div_scal__ - - procedure, private :: eq__ - generic, public :: operator(==) => eq__ - - procedure, private :: neq__ - generic, public :: operator(/=) => neq__ - - procedure, private :: pow_quat__ - procedure, private :: pow_scal__ - generic, public :: operator(**) => pow_quat__, pow_scal__ - - procedure, public :: abs => abs__ - procedure, public :: conjg => conjg__ - procedure, public :: real => real__ - procedure, public :: aimag => aimag__ - - procedure, public :: homomorphed - procedure, public :: asArray - procedure, public :: inverse - - end type - - interface assignment (=) - module procedure assign_quat__ - module procedure assign_vec__ - end interface assignment (=) - - interface quaternion - module procedure init__ - end interface quaternion - - interface abs - procedure abs__ - end interface abs - - interface dot_product - procedure dot_product__ - end interface dot_product - - interface conjg - module procedure conjg__ - end interface conjg - - interface exp - module procedure exp__ - end interface exp - - interface log - module procedure log__ - end interface log - - interface real - module procedure real__ - end interface real - - interface aimag - module procedure aimag__ - end interface aimag - - public :: & - quaternions_init, & - assignment(=), & - conjg, aimag, & - log, exp, & - abs, dot_product, & - inverse, & - real - -contains - - -!-------------------------------------------------------------------------------------------------- -!> @brief Do self test. -!-------------------------------------------------------------------------------------------------- -subroutine quaternions_init - - print'(/,a)', ' <<<+- quaternions init -+>>>'; flush(6) - - call selfTest - -end subroutine quaternions_init - - -!--------------------------------------------------------------------------------------------------- -!> @brief construct a quaternion from a 4-vector -!--------------------------------------------------------------------------------------------------- -type(quaternion) pure function init__(array) - - real(pReal), intent(in), dimension(4) :: array - - init__%w = array(1) - init__%x = array(2) - init__%y = array(3) - init__%z = array(4) - -end function init__ - - -!--------------------------------------------------------------------------------------------------- -!> @brief assign a quaternion -!--------------------------------------------------------------------------------------------------- -elemental pure subroutine assign_quat__(self,other) - - type(quaternion), intent(out) :: self - type(quaternion), intent(in) :: other - - self = [other%w,other%x,other%y,other%z] - -end subroutine assign_quat__ - - -!--------------------------------------------------------------------------------------------------- -!> @brief assign a 4-vector -!--------------------------------------------------------------------------------------------------- -pure subroutine assign_vec__(self,other) - - type(quaternion), intent(out) :: self - real(pReal), intent(in), dimension(4) :: other - - self%w = other(1) - self%x = other(2) - self%y = other(3) - self%z = other(4) - -end subroutine assign_vec__ - - -!--------------------------------------------------------------------------------------------------- -!> @brief add a quaternion -!--------------------------------------------------------------------------------------------------- -type(quaternion) elemental pure function add__(self,other) - - class(quaternion), intent(in) :: self,other - - add__ = [ self%w, self%x, self%y ,self%z] & - + [other%w, other%x, other%y,other%z] - -end function add__ - - -!--------------------------------------------------------------------------------------------------- -!> @brief return (unary positive operator) -!--------------------------------------------------------------------------------------------------- -type(quaternion) elemental pure function pos__(self) - - class(quaternion), intent(in) :: self - - pos__ = self * (+1.0_pReal) - -end function pos__ - - -!--------------------------------------------------------------------------------------------------- -!> @brief subtract a quaternion -!--------------------------------------------------------------------------------------------------- -type(quaternion) elemental pure function sub__(self,other) - - class(quaternion), intent(in) :: self,other - - sub__ = [ self%w, self%x, self%y ,self%z] & - - [other%w, other%x, other%y,other%z] - -end function sub__ - - -!--------------------------------------------------------------------------------------------------- -!> @brief negate (unary negative operator) -!--------------------------------------------------------------------------------------------------- -type(quaternion) elemental pure function neg__(self) - - class(quaternion), intent(in) :: self - - neg__ = self * (-1.0_pReal) - -end function neg__ - - -!--------------------------------------------------------------------------------------------------- -!> @brief multiply with a quaternion -!--------------------------------------------------------------------------------------------------- -type(quaternion) elemental pure function mul_quat__(self,other) - - class(quaternion), intent(in) :: self, other - - mul_quat__%w = self%w*other%w - self%x*other%x - self%y*other%y - self%z*other%z - mul_quat__%x = self%w*other%x + self%x*other%w + P * (self%y*other%z - self%z*other%y) - mul_quat__%y = self%w*other%y + self%y*other%w + P * (self%z*other%x - self%x*other%z) - mul_quat__%z = self%w*other%z + self%z*other%w + P * (self%x*other%y - self%y*other%x) - -end function mul_quat__ - - -!--------------------------------------------------------------------------------------------------- -!> @brief multiply with a scalar -!--------------------------------------------------------------------------------------------------- -type(quaternion) elemental pure function mul_scal__(self,scal) - - class(quaternion), intent(in) :: self - real(pReal), intent(in) :: scal - - mul_scal__ = [self%w,self%x,self%y,self%z]*scal - -end function mul_scal__ - - -!--------------------------------------------------------------------------------------------------- -!> @brief divide by a quaternion -!--------------------------------------------------------------------------------------------------- -type(quaternion) elemental pure function div_quat__(self,other) - - class(quaternion), intent(in) :: self, other - - div_quat__ = self * (conjg(other)/(abs(other)**2.0_pReal)) - -end function div_quat__ - - -!--------------------------------------------------------------------------------------------------- -!> @brief divide by a scalar -!--------------------------------------------------------------------------------------------------- -type(quaternion) elemental pure function div_scal__(self,scal) - - class(quaternion), intent(in) :: self - real(pReal), intent(in) :: scal - - div_scal__ = [self%w,self%x,self%y,self%z]/scal - -end function div_scal__ - - -!--------------------------------------------------------------------------------------------------- -!> @brief test equality -!--------------------------------------------------------------------------------------------------- -logical elemental pure function eq__(self,other) - - class(quaternion), intent(in) :: self,other - - eq__ = all(dEq([ self%w, self%x, self%y, self%z], & - [other%w,other%x,other%y,other%z])) - -end function eq__ - - -!--------------------------------------------------------------------------------------------------- -!> @brief test inequality -!--------------------------------------------------------------------------------------------------- -logical elemental pure function neq__(self,other) - - class(quaternion), intent(in) :: self,other - - neq__ = .not. self%eq__(other) - -end function neq__ - - -!--------------------------------------------------------------------------------------------------- -!> @brief raise to the power of a quaternion -!--------------------------------------------------------------------------------------------------- -type(quaternion) elemental pure function pow_quat__(self,expon) - - class(quaternion), intent(in) :: self - type(quaternion), intent(in) :: expon - - pow_quat__ = exp(log(self)*expon) - -end function pow_quat__ - - -!--------------------------------------------------------------------------------------------------- -!> @brief raise to the power of a scalar -!--------------------------------------------------------------------------------------------------- -type(quaternion) elemental pure function pow_scal__(self,expon) - - class(quaternion), intent(in) :: self - real(pReal), intent(in) :: expon - - pow_scal__ = exp(log(self)*expon) - -end function pow_scal__ - - -!--------------------------------------------------------------------------------------------------- -!> @brief take exponential -!--------------------------------------------------------------------------------------------------- -type(quaternion) elemental pure function exp__(a) - - class(quaternion), intent(in) :: a - real(pReal) :: absImag - - absImag = norm2(aimag(a)) - - exp__ = merge(exp(a%w) * [ cos(absImag), & - a%x/absImag * sin(absImag), & - a%y/absImag * sin(absImag), & - a%z/absImag * sin(absImag)], & - IEEE_value(1.0_pReal,IEEE_SIGNALING_NAN), & - dNeq0(absImag)) - -end function exp__ - - -!--------------------------------------------------------------------------------------------------- -!> @brief take logarithm -!--------------------------------------------------------------------------------------------------- -type(quaternion) elemental pure function log__(a) - - class(quaternion), intent(in) :: a - real(pReal) :: absImag - - absImag = norm2(aimag(a)) - - log__ = merge([log(abs(a)), & - a%x/absImag * acos(a%w/abs(a)), & - a%y/absImag * acos(a%w/abs(a)), & - a%z/absImag * acos(a%w/abs(a))], & - IEEE_value(1.0_pReal,IEEE_SIGNALING_NAN), & - dNeq0(absImag)) - -end function log__ - - -!--------------------------------------------------------------------------------------------------- -!> @brief return norm -!--------------------------------------------------------------------------------------------------- -real(pReal) elemental pure function abs__(self) - - class(quaternion), intent(in) :: self - - abs__ = norm2([self%w,self%x,self%y,self%z]) - -end function abs__ - - -!--------------------------------------------------------------------------------------------------- -!> @brief calculate dot product -!--------------------------------------------------------------------------------------------------- -real(pReal) elemental pure function dot_product__(a,b) - - class(quaternion), intent(in) :: a,b - - dot_product__ = a%w*b%w + a%x*b%x + a%y*b%y + a%z*b%z - -end function dot_product__ - - -!--------------------------------------------------------------------------------------------------- -!> @brief take conjugate complex -!--------------------------------------------------------------------------------------------------- -type(quaternion) elemental pure function conjg__(self) - - class(quaternion), intent(in) :: self - - conjg__ = [self%w,-self%x,-self%y,-self%z] - -end function conjg__ - - -!--------------------------------------------------------------------------------------------------- -!> @brief homomorph -!--------------------------------------------------------------------------------------------------- -type(quaternion) elemental pure function homomorphed(self) - - class(quaternion), intent(in) :: self - - homomorphed = - self - -end function homomorphed - - -!--------------------------------------------------------------------------------------------------- -!> @brief return as plain array -!--------------------------------------------------------------------------------------------------- -pure function asArray(self) - - real(pReal), dimension(4) :: asArray - class(quaternion), intent(in) :: self - - asArray = [self%w,self%x,self%y,self%z] - -end function asArray - - -!--------------------------------------------------------------------------------------------------- -!> @brief real part (scalar) -!--------------------------------------------------------------------------------------------------- -pure function real__(self) - - real(pReal) :: real__ - class(quaternion), intent(in) :: self - - real__ = self%w - -end function real__ - - -!--------------------------------------------------------------------------------------------------- -!> @brief imaginary part (3-vector) -!--------------------------------------------------------------------------------------------------- -pure function aimag__(self) - - real(pReal), dimension(3) :: aimag__ - class(quaternion), intent(in) :: self - - aimag__ = [self%x,self%y,self%z] - -end function aimag__ - - -!--------------------------------------------------------------------------------------------------- -!> @brief inverse -!--------------------------------------------------------------------------------------------------- -type(quaternion) elemental pure function inverse(self) - - class(quaternion), intent(in) :: self - - inverse = conjg(self)/abs(self)**2.0_pReal - -end function inverse - - -!-------------------------------------------------------------------------------------------------- -!> @brief check correctness of some quaternions functions -!-------------------------------------------------------------------------------------------------- -subroutine selfTest - - real(pReal), dimension(4) :: qu - type(quaternion) :: q, q_2 - - if(dNeq(abs(P),1.0_pReal)) error stop 'P not in {-1,+1}' - - call random_number(qu) - qu = (qu-0.5_pReal) * 2.0_pReal - q = quaternion(qu) - - q_2= qu - if(any(dNeq(q%asArray(),q_2%asArray()))) error stop 'assign_vec__' - - q_2 = q + q - if(any(dNeq(q_2%asArray(),2.0_pReal*qu))) error stop 'add__' - - q_2 = q - q - if(any(dNeq0(q_2%asArray()))) error stop 'sub__' - - q_2 = q * 5.0_pReal - if(any(dNeq(q_2%asArray(),5.0_pReal*qu))) error stop 'mul__' - - q_2 = q / 0.5_pReal - if(any(dNeq(q_2%asArray(),2.0_pReal*qu))) error stop 'div__' - - q_2 = q * 0.3_pReal - if(dNeq0(abs(q)) .and. q_2 == q) error stop 'eq__' - - q_2 = q - if(q_2 /= q) error stop 'neq__' - - if(dNeq(abs(q),norm2(qu))) error stop 'abs__' - if(dNeq(abs(q)**2.0_pReal, real(q*q%conjg()),1.0e-14_pReal)) & - error stop 'abs__/*conjg' - - if(any(dNeq(q%asArray(),qu))) error stop 'eq__' - if(dNeq(q%real(), qu(1))) error stop 'real()' - if(any(dNeq(q%aimag(), qu(2:4)))) error stop 'aimag()' - - q_2 = q%homomorphed() - if(q /= q_2* (-1.0_pReal)) error stop 'homomorphed' - if(dNeq(q_2%real(), qu(1)* (-1.0_pReal))) error stop 'homomorphed/real' - if(any(dNeq(q_2%aimag(),qu(2:4)*(-1.0_pReal)))) error stop 'homomorphed/aimag' - - q_2 = conjg(q) - if(dNeq(abs(q),abs(q_2))) error stop 'conjg/abs' - if(q /= conjg(q_2)) error stop 'conjg/involution' - if(dNeq(q_2%real(), q%real())) error stop 'conjg/real' - if(any(dNeq(q_2%aimag(),q%aimag()*(-1.0_pReal)))) error stop 'conjg/aimag' - - if(abs(q) > 0.0_pReal) then - q_2 = q * q%inverse() - if( dNeq(real(q_2), 1.0_pReal,1.0e-15_pReal)) error stop 'inverse/real' - if(any(dNeq0(aimag(q_2), 1.0e-15_pReal))) error stop 'inverse/aimag' - - q_2 = q/abs(q) - q_2 = conjg(q_2) - inverse(q_2) - if(any(dNeq0(q_2%asArray(),1.0e-15_pReal))) error stop 'inverse/conjg' - endif - if(dNeq(dot_product(qu,qu),dot_product(q,q))) error stop 'dot_product' - -#if !(defined(__GFORTRAN__) && __GNUC__ < 9) - if (norm2(aimag(q)) > 0.0_pReal) then - if (dNeq0(abs(q-exp(log(q))),1.0e-13_pReal)) error stop 'exp/log' - if (dNeq0(abs(q-log(exp(q))),1.0e-13_pReal)) error stop 'log/exp' - endif -#endif - -end subroutine selfTest - - -end module quaternions diff --git a/src/results.f90 b/src/results.f90 index bf276f561..6363e3efc 100644 --- a/src/results.f90 +++ b/src/results.f90 @@ -8,7 +8,6 @@ module results use DAMASK_interface use parallelization use IO - use rotations use HDF5_utilities #ifdef PETSc use PETSC @@ -20,27 +19,21 @@ module results integer(HID_T) :: resultsFile interface results_writeDataset - module procedure results_writeTensorDataset_real module procedure results_writeVectorDataset_real module procedure results_writeScalarDataset_real module procedure results_writeTensorDataset_int module procedure results_writeVectorDataset_int - - module procedure results_writeScalarDataset_rotation - end interface results_writeDataset interface results_addAttribute - module procedure results_addAttribute_real module procedure results_addAttribute_int module procedure results_addAttribute_str module procedure results_addAttribute_int_array module procedure results_addAttribute_real_array - end interface results_addAttribute public :: & @@ -56,7 +49,7 @@ module results results_setLink, & results_addAttribute, & results_removeLink, & - results_mapping_constituent, & + results_mapping_phase, & results_mapping_homogenization contains @@ -74,7 +67,7 @@ subroutine results_init(restart) if(.not. restart) then resultsFile = HDF5_openFile(trim(getSolverJobName())//'.hdf5','w',.true.) call results_addAttribute('DADF5_version_major',0) - call results_addAttribute('DADF5_version_minor',9) + call results_addAttribute('DADF5_version_minor',11) call results_addAttribute('DAMASK_version',DAMASKVERSION) call get_command(commandLine) call results_addAttribute('Call',trim(commandLine)) @@ -118,8 +111,6 @@ subroutine results_addIncrement(inc,time) call results_closeGroup(results_addGroup(trim('inc'//trim(adjustl(incChar))))) call results_setLink(trim('inc'//trim(adjustl(incChar))),'current') call results_addAttribute('time/s',time,trim('inc'//trim(adjustl(incChar)))) - call results_closeGroup(results_addGroup('current/phase')) - call results_closeGroup(results_addGroup('current/homogenization')) end subroutine results_addIncrement @@ -465,46 +456,14 @@ subroutine results_writeTensorDataset_int(group,dataset,label,description,SIunit end subroutine results_writeTensorDataset_int -!-------------------------------------------------------------------------------------------------- -!> @brief stores a scalar dataset in a group -!-------------------------------------------------------------------------------------------------- -subroutine results_writeScalarDataset_rotation(group,dataset,label,description,lattice_structure) - - character(len=*), intent(in) :: label,group,description - character(len=*), intent(in), optional :: lattice_structure - type(rotation), intent(inout), dimension(:) :: dataset - - integer(HID_T) :: groupHandle - - groupHandle = results_openGroup(group) - -#ifdef PETSc - call HDF5_write(groupHandle,dataset,label,.true.) -#else - call HDF5_write(groupHandle,dataset,label,.false.) -#endif - - if (HDF5_objectExists(groupHandle,label)) & - call HDF5_addAttribute(groupHandle,'Description',description,label) - if (HDF5_objectExists(groupHandle,label) .and. present(lattice_structure)) & - call HDF5_addAttribute(groupHandle,'Lattice',lattice_structure,label) - if (HDF5_objectExists(groupHandle,label)) & - call HDF5_addAttribute(groupHandle,'Creator','DAMASK '//DAMASKVERSION,label) - if (HDF5_objectExists(groupHandle,label)) & - call HDF5_addAttribute(groupHandle,'Created',now(),label) - call HDF5_closeGroup(groupHandle) - -end subroutine results_writeScalarDataset_rotation - - !-------------------------------------------------------------------------------------------------- !> @brief adds the unique mapping from spatial position and constituent ID to results !-------------------------------------------------------------------------------------------------- -subroutine results_mapping_constituent(phaseAt,memberAtLocal,label) +subroutine results_mapping_phase(phaseAt,memberAtLocal,label) integer, dimension(:,:), intent(in) :: phaseAt !< phase section at (constituent,element) - integer, dimension(:,:,:), intent(in) :: memberAtLocal !< phase member at (constituent,IP,element) - character(len=pStringLen), dimension(:), intent(in) :: label !< label of each phase section + integer, dimension(:,:,:), intent(in) :: memberAtLocal !< phase member at (constituent,IP,element) + character(len=*), dimension(:), intent(in) :: label !< label of each phase section integer, dimension(size(memberAtLocal,1),size(memberAtLocal,2),size(memberAtLocal,3)) :: & phaseAtMaterialpoint, & @@ -527,10 +486,50 @@ subroutine results_mapping_constituent(phaseAt,memberAtLocal,label) plist_id, & dt_id - integer(SIZE_T) :: type_size_string, type_size_int integer :: hdferr, ierr, i +!-------------------------------------------------------------------------------------------------- +! prepare MPI communication (transparent for non-MPI runs) + call h5pcreate_f(H5P_DATASET_XFER_F, plist_id, hdferr) + if(hdferr < 0) error stop 'HDF5 error' + memberOffset = 0 + do i=1, size(label) + memberOffset(i,worldrank) = count(phaseAt == i)*size(memberAtLocal,2) ! number of points/instance of this process + enddo + writeSize = 0 + writeSize(worldrank) = size(memberAtLocal(1,:,:)) ! total number of points by this process + +!-------------------------------------------------------------------------------------------------- +! MPI settings and communication +#ifdef PETSc + call h5pset_dxpl_mpio_f(plist_id, H5FD_MPIO_COLLECTIVE_F, hdferr) + if(hdferr < 0) error stop 'HDF5 error' + + call MPI_allreduce(MPI_IN_PLACE,writeSize,worldsize,MPI_INT,MPI_SUM,PETSC_COMM_WORLD,ierr) ! get output at each process + if(ierr /= 0) error stop 'MPI error' + + call MPI_allreduce(MPI_IN_PLACE,memberOffset,size(memberOffset),MPI_INT,MPI_SUM,PETSC_COMM_WORLD,ierr)! get offset at each process + if(ierr /= 0) error stop 'MPI error' +#endif + + myShape = int([size(phaseAt,1),writeSize(worldrank)], HSIZE_T) + myOffset = int([0,sum(writeSize(0:worldrank-1))], HSIZE_T) + totalShape = int([size(phaseAt,1),sum(writeSize)], HSIZE_T) + + +!--------------------------------------------------------------------------------------------------- +! expand phaseAt to consider IPs (is not stored per IP) + do i = 1, size(phaseAtMaterialpoint,2) + phaseAtMaterialpoint(:,i,:) = phaseAt + enddo + +!--------------------------------------------------------------------------------------------------- +! renumber member from my process to all processes + do i = 1, size(label) + where(phaseAtMaterialpoint == i) memberAtGlobal = memberAtLocal + sum(memberOffset(i,0:worldrank-1)) -1 ! convert to 0-based + enddo + !--------------------------------------------------------------------------------------------------- ! compound type: name of phase section + position/index within results array call h5tcopy_f(H5T_NATIVE_CHARACTER, dt_id, hdferr) @@ -565,34 +564,6 @@ subroutine results_mapping_constituent(phaseAt,memberAtLocal,label) call h5tclose_f(dt_id, hdferr) if(hdferr < 0) error stop 'HDF5 error' -!-------------------------------------------------------------------------------------------------- -! prepare MPI communication (transparent for non-MPI runs) - call h5pcreate_f(H5P_DATASET_XFER_F, plist_id, hdferr) - if(hdferr < 0) error stop 'HDF5 error' - memberOffset = 0 - do i=1, size(label) - memberOffset(i,worldrank) = count(phaseAt == i)*size(memberAtLocal,2) ! number of points/instance of this process - enddo - writeSize = 0 - writeSize(worldrank) = size(memberAtLocal(1,:,:)) ! total number of points by this process - -!-------------------------------------------------------------------------------------------------- -! MPI settings and communication -#ifdef PETSc - call h5pset_dxpl_mpio_f(plist_id, H5FD_MPIO_COLLECTIVE_F, hdferr) - if(hdferr < 0) error stop 'HDF5 error' - - call MPI_allreduce(MPI_IN_PLACE,writeSize,worldsize,MPI_INT,MPI_SUM,PETSC_COMM_WORLD,ierr) ! get output at each process - if(ierr /= 0) error stop 'MPI error' - - call MPI_allreduce(MPI_IN_PLACE,memberOffset,size(memberOffset),MPI_INT,MPI_SUM,PETSC_COMM_WORLD,ierr)! get offset at each process - if(ierr /= 0) error stop 'MPI error' -#endif - - myShape = int([size(phaseAt,1),writeSize(worldrank)], HSIZE_T) - myOffset = int([0,sum(writeSize(0:worldrank-1))], HSIZE_T) - totalShape = int([size(phaseAt,1),sum(writeSize)], HSIZE_T) - !-------------------------------------------------------------------------------------------------- ! create dataspace in memory (local shape = hyperslab) and in file (global shape) call h5screate_simple_f(2,myShape,memspace_id,hdferr,myShape) @@ -604,18 +575,6 @@ subroutine results_mapping_constituent(phaseAt,memberAtLocal,label) call h5sselect_hyperslab_f(filespace_id, H5S_SELECT_SET_F, myOffset, myShape, hdferr) if(hdferr < 0) error stop 'HDF5 error' -!--------------------------------------------------------------------------------------------------- -! expand phaseAt to consider IPs (is not stored per IP) - do i = 1, size(phaseAtMaterialpoint,2) - phaseAtMaterialpoint(:,i,:) = phaseAt - enddo - -!--------------------------------------------------------------------------------------------------- -! renumber member from my process to all processes - do i = 1, size(label) - where(phaseAtMaterialpoint == i) memberAtGlobal = memberAtLocal + sum(memberOffset(i,0:worldrank-1)) -1 ! convert to 0-based - enddo - !-------------------------------------------------------------------------------------------------- ! write the components of the compound type individually call h5pset_preserve_f(plist_id, .TRUE., hdferr) @@ -649,7 +608,7 @@ subroutine results_mapping_constituent(phaseAt,memberAtLocal,label) if(hdferr < 0) error stop 'HDF5 error' call h5tclose_f(position_id, hdferr) -end subroutine results_mapping_constituent +end subroutine results_mapping_phase !-------------------------------------------------------------------------------------------------- @@ -658,8 +617,8 @@ end subroutine results_mapping_constituent subroutine results_mapping_homogenization(homogenizationAt,memberAtLocal,label) integer, dimension(:), intent(in) :: homogenizationAt !< homogenization section at (element) - integer, dimension(:,:), intent(in) :: memberAtLocal !< homogenization member at (IP,element) - character(len=pStringLen), dimension(:), intent(in) :: label !< label of each homogenization section + integer, dimension(:,:), intent(in) :: memberAtLocal !< homogenization member at (IP,element) + character(len=*), dimension(:), intent(in) :: label !< label of each homogenization section integer, dimension(size(memberAtLocal,1),size(memberAtLocal,2)) :: & homogenizationAtMaterialpoint, & @@ -682,10 +641,51 @@ subroutine results_mapping_homogenization(homogenizationAt,memberAtLocal,label) plist_id, & dt_id - integer(SIZE_T) :: type_size_string, type_size_int integer :: hdferr, ierr, i + +!-------------------------------------------------------------------------------------------------- +! prepare MPI communication (transparent for non-MPI runs) + call h5pcreate_f(H5P_DATASET_XFER_F, plist_id, hdferr) + if(hdferr < 0) error stop 'HDF5 error' + memberOffset = 0 + do i=1, size(label) + memberOffset(i,worldrank) = count(homogenizationAt == i)*size(memberAtLocal,1) ! number of points/instance of this process + enddo + writeSize = 0 + writeSize(worldrank) = size(memberAtLocal) ! total number of points by this process + +!-------------------------------------------------------------------------------------------------- +! MPI settings and communication +#ifdef PETSc + call h5pset_dxpl_mpio_f(plist_id, H5FD_MPIO_COLLECTIVE_F, hdferr) + if(hdferr < 0) error stop 'HDF5 error' + + call MPI_allreduce(MPI_IN_PLACE,writeSize,worldsize,MPI_INT,MPI_SUM,PETSC_COMM_WORLD,ierr) ! get output at each process + if(ierr /= 0) error stop 'MPI error' + + call MPI_allreduce(MPI_IN_PLACE,memberOffset,size(memberOffset),MPI_INT,MPI_SUM,PETSC_COMM_WORLD,ierr)! get offset at each process + if(ierr /= 0) error stop 'MPI error' +#endif + + myShape = int([writeSize(worldrank)], HSIZE_T) + myOffset = int([sum(writeSize(0:worldrank-1))], HSIZE_T) + totalShape = int([sum(writeSize)], HSIZE_T) + + +!--------------------------------------------------------------------------------------------------- +! expand phaseAt to consider IPs (is not stored per IP) + do i = 1, size(homogenizationAtMaterialpoint,1) + homogenizationAtMaterialpoint(i,:) = homogenizationAt + enddo + +!--------------------------------------------------------------------------------------------------- +! renumber member from my process to all processes + do i = 1, size(label) + where(homogenizationAtMaterialpoint == i) memberAtGlobal = memberAtLocal + sum(memberOffset(i,0:worldrank-1)) - 1 ! convert to 0-based + enddo + !--------------------------------------------------------------------------------------------------- ! compound type: name of phase section + position/index within results array call h5tcopy_f(H5T_NATIVE_CHARACTER, dt_id, hdferr) @@ -720,34 +720,6 @@ subroutine results_mapping_homogenization(homogenizationAt,memberAtLocal,label) call h5tclose_f(dt_id, hdferr) if(hdferr < 0) error stop 'HDF5 error' -!-------------------------------------------------------------------------------------------------- -! prepare MPI communication (transparent for non-MPI runs) - call h5pcreate_f(H5P_DATASET_XFER_F, plist_id, hdferr) - if(hdferr < 0) error stop 'HDF5 error' - memberOffset = 0 - do i=1, size(label) - memberOffset(i,worldrank) = count(homogenizationAt == i)*size(memberAtLocal,1) ! number of points/instance of this process - enddo - writeSize = 0 - writeSize(worldrank) = size(memberAtLocal) ! total number of points by this process - -!-------------------------------------------------------------------------------------------------- -! MPI settings and communication -#ifdef PETSc - call h5pset_dxpl_mpio_f(plist_id, H5FD_MPIO_COLLECTIVE_F, hdferr) - if(hdferr < 0) error stop 'HDF5 error' - - call MPI_allreduce(MPI_IN_PLACE,writeSize,worldsize,MPI_INT,MPI_SUM,PETSC_COMM_WORLD,ierr) ! get output at each process - if(ierr /= 0) error stop 'MPI error' - - call MPI_allreduce(MPI_IN_PLACE,memberOffset,size(memberOffset),MPI_INT,MPI_SUM,PETSC_COMM_WORLD,ierr)! get offset at each process - if(ierr /= 0) error stop 'MPI error' -#endif - - myShape = int([writeSize(worldrank)], HSIZE_T) - myOffset = int([sum(writeSize(0:worldrank-1))], HSIZE_T) - totalShape = int([sum(writeSize)], HSIZE_T) - !-------------------------------------------------------------------------------------------------- ! create dataspace in memory (local shape = hyperslab) and in file (global shape) call h5screate_simple_f(1,myShape,memspace_id,hdferr,myShape) @@ -759,18 +731,6 @@ subroutine results_mapping_homogenization(homogenizationAt,memberAtLocal,label) call h5sselect_hyperslab_f(filespace_id, H5S_SELECT_SET_F, myOffset, myShape, hdferr) if(hdferr < 0) error stop 'HDF5 error' -!--------------------------------------------------------------------------------------------------- -! expand phaseAt to consider IPs (is not stored per IP) - do i = 1, size(homogenizationAtMaterialpoint,1) - homogenizationAtMaterialpoint(i,:) = homogenizationAt - enddo - -!--------------------------------------------------------------------------------------------------- -! renumber member from my process to all processes - do i = 1, size(label) - where(homogenizationAtMaterialpoint == i) memberAtGlobal = memberAtLocal + sum(memberOffset(i,0:worldrank-1)) - 1 ! convert to 0-based - enddo - !-------------------------------------------------------------------------------------------------- ! write the components of the compound type individually call h5pset_preserve_f(plist_id, .TRUE., hdferr) diff --git a/src/rotations.f90 b/src/rotations.f90 index 888e73762..57dd16b53 100644 --- a/src/rotations.f90 +++ b/src/rotations.f90 @@ -47,16 +47,16 @@ !--------------------------------------------------------------------------------------------------- module rotations - use prec use IO use math - use quaternions implicit none private + real(pReal), parameter :: P = -1.0_pReal !< parameter for orientation conversion. + type, public :: rotation - type(quaternion) :: q + real(pReal), dimension(4) :: q contains procedure, public :: asQuaternion procedure, public :: asEulers @@ -103,7 +103,6 @@ contains !-------------------------------------------------------------------------------------------------- subroutine rotations_init - call quaternions_init print'(/,a)', ' <<<+- rotations init -+>>>'; flush(IO_STDOUT) print*, 'Rowenhorst et al., Modelling and Simulation in Materials Science and Engineering 23:083501, 2015' @@ -122,7 +121,7 @@ pure function asQuaternion(self) class(rotation), intent(in) :: self real(pReal), dimension(4) :: asQuaternion - asQuaternion = self%q%asArray() + asQuaternion = self%q end function asQuaternion !--------------------------------------------------------------------------------------------------- @@ -131,7 +130,7 @@ pure function asEulers(self) class(rotation), intent(in) :: self real(pReal), dimension(3) :: asEulers - asEulers = qu2eu(self%q%asArray()) + asEulers = qu2eu(self%q) end function asEulers !--------------------------------------------------------------------------------------------------- @@ -140,7 +139,7 @@ pure function asAxisAngle(self) class(rotation), intent(in) :: self real(pReal), dimension(4) :: asAxisAngle - asAxisAngle = qu2ax(self%q%asArray()) + asAxisAngle = qu2ax(self%q) end function asAxisAngle !--------------------------------------------------------------------------------------------------- @@ -149,7 +148,7 @@ pure function asMatrix(self) class(rotation), intent(in) :: self real(pReal), dimension(3,3) :: asMatrix - asMatrix = qu2om(self%q%asArray()) + asMatrix = qu2om(self%q) end function asMatrix !--------------------------------------------------------------------------------------------------- @@ -158,7 +157,7 @@ pure function asRodrigues(self) class(rotation), intent(in) :: self real(pReal), dimension(4) :: asRodrigues - asRodrigues = qu2ro(self%q%asArray()) + asRodrigues = qu2ro(self%q) end function asRodrigues !--------------------------------------------------------------------------------------------------- @@ -167,7 +166,7 @@ pure function asHomochoric(self) class(rotation), intent(in) :: self real(pReal), dimension(3) :: asHomochoric - asHomochoric = qu2ho(self%q%asArray()) + asHomochoric = qu2ho(self%q) end function asHomochoric @@ -259,7 +258,7 @@ pure elemental function rotRot__(self,R) result(rRot) type(rotation) :: rRot class(rotation), intent(in) :: self,R - rRot = rotation(self%q*R%q) + rRot = rotation(multiply_quaternion(self%q,R%q)) call rRot%standardize() end function rotRot__ @@ -272,14 +271,14 @@ pure elemental subroutine standardize(self) class(rotation), intent(inout) :: self - if (real(self%q) < 0.0_pReal) self%q = self%q%homomorphed() + if (self%q(1) < 0.0_pReal) self%q = - self%q end subroutine standardize !--------------------------------------------------------------------------------------------------- !> @author Marc De Graef, Carnegie Mellon University -!> @brief rotate a vector passively (default) or actively +!> @brief Rotate a vector passively (default) or actively. !--------------------------------------------------------------------------------------------------- pure function rotVector(self,v,active) result(vRot) @@ -288,9 +287,8 @@ pure function rotVector(self,v,active) result(vRot) real(pReal), intent(in), dimension(3) :: v logical, intent(in), optional :: active - real(pReal), dimension(3) :: v_normed - type(quaternion) :: q - logical :: passive + real(pReal), dimension(4) :: v_normed, q + logical :: passive if (present(active)) then passive = .not. active @@ -301,13 +299,13 @@ pure function rotVector(self,v,active) result(vRot) if (dEq0(norm2(v))) then vRot = v else - v_normed = v/norm2(v) + v_normed = [0.0_pReal,v]/norm2(v) if (passive) then - q = self%q * (quaternion([0.0_pReal, v_normed(1), v_normed(2), v_normed(3)]) * conjg(self%q) ) + q = multiply_quaternion(self%q, multiply_quaternion(v_normed, conjugate_quaternion(self%q))) else - q = conjg(self%q) * (quaternion([0.0_pReal, v_normed(1), v_normed(2), v_normed(3)]) * self%q ) + q = multiply_quaternion(conjugate_quaternion(self%q), multiply_quaternion(v_normed, self%q)) endif - vRot = q%aimag()*norm2(v) + vRot = q(2:4)*norm2(v) endif end function rotVector @@ -315,8 +313,8 @@ end function rotVector !--------------------------------------------------------------------------------------------------- !> @author Marc De Graef, Carnegie Mellon University -!> @brief rotate a rank-2 tensor passively (default) or actively -!> @details: rotation is based on rotation matrix +!> @brief Rotate a rank-2 tensor passively (default) or actively. +!> @details: Rotation is based on rotation matrix !--------------------------------------------------------------------------------------------------- pure function rotTensor2(self,T,active) result(tRot) @@ -403,7 +401,7 @@ pure elemental function misorientation(self,other) type(rotation) :: misorientation class(rotation), intent(in) :: self, other - misorientation%q = other%q * conjg(self%q) + misorientation%q = multiply_quaternion(other%q, conjugate_quaternion(self%q)) end function misorientation @@ -1338,7 +1336,7 @@ end function cu2ho !-------------------------------------------------------------------------- !> @author Marc De Graef, Carnegie Mellon University !> @author Martin Diehl, Max-Planck-Institut für Eisenforschung GmbH -!> @brief determine to which pyramid a point in a cubic grid belongs +!> @brief Determine to which pyramid a point in a cubic grid belongs. !-------------------------------------------------------------------------- pure function GetPyramidOrder(xyz) @@ -1362,7 +1360,39 @@ end function GetPyramidOrder !-------------------------------------------------------------------------------------------------- -!> @brief check correctness of some rotations functions +!> @brief Multiply two quaternions. +!-------------------------------------------------------------------------------------------------- +pure function multiply_quaternion(qu1,qu2) + + real(pReal), dimension(4), intent(in) :: qu1, qu2 + real(pReal), dimension(4) :: multiply_quaternion + + + multiply_quaternion(1) = qu1(1)*qu2(1) - qu1(2)*qu2(2) - qu1(3)*qu2(3) - qu1(4)*qu2(4) + multiply_quaternion(2) = qu1(1)*qu2(2) + qu1(2)*qu2(1) + P * (qu1(3)*qu2(4) - qu1(4)*qu2(3)) + multiply_quaternion(3) = qu1(1)*qu2(3) + qu1(3)*qu2(1) + P * (qu1(4)*qu2(2) - qu1(2)*qu2(4)) + multiply_quaternion(4) = qu1(1)*qu2(4) + qu1(4)*qu2(1) + P * (qu1(2)*qu2(3) - qu1(3)*qu2(2)) + +end function multiply_quaternion + + +!-------------------------------------------------------------------------------------------------- +!> @brief Calculate conjugate complex of a quaternion. +!-------------------------------------------------------------------------------------------------- +pure function conjugate_quaternion(qu) + + real(pReal), dimension(4), intent(in) :: qu + real(pReal), dimension(4) :: conjugate_quaternion + + + conjugate_quaternion = [qu(1), -qu(2), -qu(3), -qu(4)] + + +end function conjugate_quaternion + + +!-------------------------------------------------------------------------------------------------- +!> @brief Check correctness of some rotations functions. !-------------------------------------------------------------------------------------------------- subroutine selfTest @@ -1374,7 +1404,8 @@ subroutine selfTest real :: A,B integer :: i - do i=1,10 + + do i = 1, 10 #if defined(__GFORTRAN__) && __GNUC__<9 if(i<7) cycle diff --git a/src/source_damage_anisoBrittle.f90 b/src/source_damage_anisoBrittle.f90 index ca8d6ec2b..0f923ceba 100644 --- a/src/source_damage_anisoBrittle.f90 +++ b/src/source_damage_anisoBrittle.f90 @@ -120,10 +120,10 @@ end function source_damage_anisoBrittle_init !-------------------------------------------------------------------------------------------------- !> @brief calculates derived quantities from state !-------------------------------------------------------------------------------------------------- -module subroutine source_damage_anisoBrittle_dotState(S, ipc, ip, el) +module subroutine source_damage_anisoBrittle_dotState(S, co, ip, el) integer, intent(in) :: & - ipc, & !< component-ID of integration point + co, & !< component-ID of integration point ip, & !< integration point el !< element real(pReal), intent(in), dimension(3,3) :: & @@ -139,11 +139,11 @@ module subroutine source_damage_anisoBrittle_dotState(S, ipc, ip, el) real(pReal) :: & traction_d, traction_t, traction_n, traction_crit - phase = material_phaseAt(ipc,el) - constituent = material_phasememberAt(ipc,ip,el) + phase = material_phaseAt(co,el) + constituent = material_phasememberAt(co,ip,el) sourceOffset = source_damage_anisoBrittle_offset(phase) homog = material_homogenizationAt(el) - damageOffset = damageMapping(homog)%p(ip,el) + damageOffset = material_homogenizationMemberAt(ip,el) associate(prm => param(source_damage_anisoBrittle_instance(phase))) sourceState(phase)%p(sourceOffset)%dotState(1,constituent) = 0.0_pReal diff --git a/src/source_damage_anisoDuctile.f90 b/src/source_damage_anisoDuctile.f90 index 601ec2531..6f71fc145 100644 --- a/src/source_damage_anisoDuctile.f90 +++ b/src/source_damage_anisoDuctile.f90 @@ -107,10 +107,10 @@ end function source_damage_anisoDuctile_init !-------------------------------------------------------------------------------------------------- !> @brief calculates derived quantities from state !-------------------------------------------------------------------------------------------------- -module subroutine source_damage_anisoDuctile_dotState(ipc, ip, el) +module subroutine source_damage_anisoDuctile_dotState(co, ip, el) integer, intent(in) :: & - ipc, & !< component-ID of integration point + co, & !< component-ID of integration point ip, & !< integration point el !< element @@ -121,11 +121,11 @@ module subroutine source_damage_anisoDuctile_dotState(ipc, ip, el) damageOffset, & homog - phase = material_phaseAt(ipc,el) - constituent = material_phasememberAt(ipc,ip,el) + phase = material_phaseAt(co,el) + constituent = material_phasememberAt(co,ip,el) sourceOffset = source_damage_anisoDuctile_offset(phase) homog = material_homogenizationAt(el) - damageOffset = damageMapping(homog)%p(ip,el) + damageOffset = material_homogenizationMemberAt(ip,el) associate(prm => param(source_damage_anisoDuctile_instance(phase))) sourceState(phase)%p(sourceOffset)%dotState(1,constituent) & diff --git a/src/source_damage_isoBrittle.f90 b/src/source_damage_isoBrittle.f90 index 7fcf17ee0..8c768b08d 100644 --- a/src/source_damage_isoBrittle.f90 +++ b/src/source_damage_isoBrittle.f90 @@ -94,10 +94,10 @@ end function source_damage_isoBrittle_init !-------------------------------------------------------------------------------------------------- !> @brief calculates derived quantities from state !-------------------------------------------------------------------------------------------------- -module subroutine source_damage_isoBrittle_deltaState(C, Fe, ipc, ip, el) +module subroutine source_damage_isoBrittle_deltaState(C, Fe, co, ip, el) integer, intent(in) :: & - ipc, & !< component-ID of integration point + co, & !< component-ID of integration point ip, & !< integration point el !< element real(pReal), intent(in), dimension(3,3) :: & @@ -114,8 +114,8 @@ module subroutine source_damage_isoBrittle_deltaState(C, Fe, ipc, ip, el) real(pReal) :: & strainenergy - phase = material_phaseAt(ipc,el) !< phase ID at ipc,ip,el - constituent = material_phasememberAt(ipc,ip,el) !< state array offset for phase ID at ipc,ip,el + phase = material_phaseAt(co,el) !< phase ID at co,ip,el + constituent = material_phasememberAt(co,ip,el) !< state array offset for phase ID at co,ip,el sourceOffset = source_damage_isoBrittle_offset(phase) strain = 0.5_pReal*math_sym33to6(matmul(transpose(Fe),Fe)-math_I3) diff --git a/src/source_damage_isoDuctile.f90 b/src/source_damage_isoDuctile.f90 index 1bff20570..86222bbf9 100644 --- a/src/source_damage_isoDuctile.f90 +++ b/src/source_damage_isoDuctile.f90 @@ -98,10 +98,10 @@ end function source_damage_isoDuctile_init !-------------------------------------------------------------------------------------------------- !> @brief calculates derived quantities from state !-------------------------------------------------------------------------------------------------- -module subroutine source_damage_isoDuctile_dotState(ipc, ip, el) +module subroutine source_damage_isoDuctile_dotState(co, ip, el) integer, intent(in) :: & - ipc, & !< component-ID of integration point + co, & !< component-ID of integration point ip, & !< integration point el !< element @@ -112,11 +112,11 @@ module subroutine source_damage_isoDuctile_dotState(ipc, ip, el) damageOffset, & homog - phase = material_phaseAt(ipc,el) - constituent = material_phasememberAt(ipc,ip,el) + phase = material_phaseAt(co,el) + constituent = material_phasememberAt(co,ip,el) sourceOffset = source_damage_isoDuctile_offset(phase) homog = material_homogenizationAt(el) - damageOffset = damageMapping(homog)%p(ip,el) + damageOffset = material_homogenizationMemberAt(ip,el) associate(prm => param(source_damage_isoDuctile_instance(phase))) sourceState(phase)%p(sourceOffset)%dotState(1,constituent) = & diff --git a/src/thermal_adiabatic.f90 b/src/thermal_adiabatic.f90 deleted file mode 100644 index aa807924c..000000000 --- a/src/thermal_adiabatic.f90 +++ /dev/null @@ -1,229 +0,0 @@ -!-------------------------------------------------------------------------------------------------- -!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH -!> @brief material subroutine for adiabatic temperature evolution -!-------------------------------------------------------------------------------------------------- -module thermal_adiabatic - use prec - use config - use material - use results - use constitutive - use YAML_types - use crystallite - use lattice - - implicit none - private - - type :: tParameters - character(len=pStringLen), allocatable, dimension(:) :: & - output - end type tParameters - - type(tparameters), dimension(:), allocatable :: & - param - - public :: & - thermal_adiabatic_init, & - thermal_adiabatic_updateState, & - thermal_adiabatic_getSourceAndItsTangent, & - thermal_adiabatic_getSpecificHeat, & - thermal_adiabatic_getMassDensity, & - thermal_adiabatic_results - -contains - - -!-------------------------------------------------------------------------------------------------- -!> @brief module initialization -!> @details reads in material parameters, allocates arrays, and does sanity checks -!-------------------------------------------------------------------------------------------------- -subroutine thermal_adiabatic_init - - integer :: maxNinstances,h,Nmaterialpoints - class(tNode), pointer :: & - material_homogenization, & - homog, & - homogThermal - - print'(/,a)', ' <<<+- thermal_adiabatic init -+>>>'; flush(6) - - maxNinstances = count(thermal_type == THERMAL_adiabatic_ID) - if (maxNinstances == 0) return - - allocate(param(maxNinstances)) - - material_homogenization => config_material%get('homogenization') - do h = 1, size(material_name_homogenization) - if (thermal_type(h) /= THERMAL_adiabatic_ID) cycle - homog => material_homogenization%get(h) - homogThermal => homog%get('thermal') - - associate(prm => param(thermal_typeInstance(h))) - -#if defined (__GFORTRAN__) - prm%output = output_asStrings(homogThermal) -#else - prm%output = homogThermal%get_asStrings('output',defaultVal=emptyStringArray) -#endif - - Nmaterialpoints=count(material_homogenizationAt==h) - thermalState(h)%sizeState = 1 - allocate(thermalState(h)%state0 (1,Nmaterialpoints), source=thermal_initialT(h)) - allocate(thermalState(h)%subState0(1,Nmaterialpoints), source=thermal_initialT(h)) - allocate(thermalState(h)%state (1,Nmaterialpoints), source=thermal_initialT(h)) - - thermalMapping(h)%p => material_homogenizationMemberAt - deallocate(temperature(h)%p) - temperature(h)%p => thermalState(h)%state(1,:) - deallocate(temperatureRate(h)%p) - allocate (temperatureRate(h)%p(Nmaterialpoints), source=0.0_pReal) - - end associate - enddo - -end subroutine thermal_adiabatic_init - - -!-------------------------------------------------------------------------------------------------- -!> @brief calculates adiabatic change in temperature based on local heat generation model -!-------------------------------------------------------------------------------------------------- -function thermal_adiabatic_updateState(subdt, ip, el) - - integer, intent(in) :: & - ip, & !< integration point number - el !< element number - real(pReal), intent(in) :: & - subdt - - logical, dimension(2) :: & - thermal_adiabatic_updateState - integer :: & - homog, & - offset - real(pReal) :: & - T, Tdot, dTdot_dT - - homog = material_homogenizationAt(el) - offset = material_homogenizationMemberAt(ip,el) - - T = thermalState(homog)%subState0(1,offset) - call thermal_adiabatic_getSourceAndItsTangent(Tdot, dTdot_dT, T, ip, el) - T = T + subdt*Tdot/(thermal_adiabatic_getSpecificHeat(ip,el)*thermal_adiabatic_getMassDensity(ip,el)) - - thermal_adiabatic_updateState = [ abs(T - thermalState(homog)%state(1,offset)) & - <= 1.0e-2_pReal & - .or. abs(T - thermalState(homog)%state(1,offset)) & - <= 1.0e-6_pReal*abs(thermalState(homog)%state(1,offset)), & - .true.] - - temperature (homog)%p(thermalMapping(homog)%p(ip,el)) = T - temperatureRate(homog)%p(thermalMapping(homog)%p(ip,el)) = & - (thermalState(homog)%state(1,offset) - thermalState(homog)%subState0(1,offset))/(subdt+tiny(0.0_pReal)) - -end function thermal_adiabatic_updateState - - -!-------------------------------------------------------------------------------------------------- -!> @brief returns heat generation rate -!-------------------------------------------------------------------------------------------------- -subroutine thermal_adiabatic_getSourceAndItsTangent(Tdot, dTdot_dT, T, ip, el) - - integer, intent(in) :: & - ip, & !< integration point number - el !< element number - real(pReal), intent(in) :: & - T - real(pReal), intent(out) :: & - Tdot, dTdot_dT - integer :: & - homog - - Tdot = 0.0_pReal - dTdot_dT = 0.0_pReal - - homog = material_homogenizationAt(el) - call constitutive_thermal_getRateAndItsTangents(TDot, dTDot_dT, T, crystallite_S, crystallite_Lp, ip, el) - - Tdot = Tdot/real(homogenization_Nconstituents(homog),pReal) - dTdot_dT = dTdot_dT/real(homogenization_Nconstituents(homog),pReal) - -end subroutine thermal_adiabatic_getSourceAndItsTangent - - -!-------------------------------------------------------------------------------------------------- -!> @brief returns homogenized specific heat capacity -!-------------------------------------------------------------------------------------------------- -function thermal_adiabatic_getSpecificHeat(ip,el) - - integer, intent(in) :: & - ip, & !< integration point number - el !< element number - - real(pReal) :: & - thermal_adiabatic_getSpecificHeat - integer :: & - grain - - thermal_adiabatic_getSpecificHeat = 0.0_pReal - - do grain = 1, homogenization_Nconstituents(material_homogenizationAt(el)) - thermal_adiabatic_getSpecificHeat = thermal_adiabatic_getSpecificHeat & - + lattice_c_p(material_phaseAt(grain,el)) - enddo - - thermal_adiabatic_getSpecificHeat = thermal_adiabatic_getSpecificHeat & - / real(homogenization_Nconstituents(material_homogenizationAt(el)),pReal) - -end function thermal_adiabatic_getSpecificHeat - - -!-------------------------------------------------------------------------------------------------- -!> @brief returns homogenized mass density -!-------------------------------------------------------------------------------------------------- -function thermal_adiabatic_getMassDensity(ip,el) - - integer, intent(in) :: & - ip, & !< integration point number - el !< element number - real(pReal) :: & - thermal_adiabatic_getMassDensity - integer :: & - grain - - thermal_adiabatic_getMassDensity = 0.0_pReal - - do grain = 1, homogenization_Nconstituents(material_homogenizationAt(el)) - thermal_adiabatic_getMassDensity = thermal_adiabatic_getMassDensity & - + lattice_rho(material_phaseAt(grain,el)) - enddo - - thermal_adiabatic_getMassDensity = thermal_adiabatic_getMassDensity & - / real(homogenization_Nconstituents(material_homogenizationAt(el)),pReal) - -end function thermal_adiabatic_getMassDensity - - -!-------------------------------------------------------------------------------------------------- -!> @brief writes results to HDF5 output file -!-------------------------------------------------------------------------------------------------- -subroutine thermal_adiabatic_results(homog,group) - - integer, intent(in) :: homog - character(len=*), intent(in) :: group - - integer :: o - - associate(prm => param(damage_typeInstance(homog))) - outputsLoop: do o = 1,size(prm%output) - select case(trim(prm%output(o))) - case('T') - call results_writeDataset(group,temperature(homog)%p,'T',& - 'temperature','K') - end select - enddo outputsLoop - end associate - -end subroutine thermal_adiabatic_results - -end module thermal_adiabatic diff --git a/src/thermal_conduction.f90 b/src/thermal_conduction.f90 index daa7391a9..d30e50677 100644 --- a/src/thermal_conduction.f90 +++ b/src/thermal_conduction.f90 @@ -8,7 +8,6 @@ module thermal_conduction use config use lattice use results - use crystallite use constitutive use YAML_types @@ -66,15 +65,8 @@ subroutine thermal_conduction_init #endif Nmaterialpoints=count(material_homogenizationAt==h) - thermalState(h)%sizeState = 0 - allocate(thermalState(h)%state0 (0,Nmaterialpoints)) - allocate(thermalState(h)%subState0(0,Nmaterialpoints)) - allocate(thermalState(h)%state (0,Nmaterialpoints)) - thermalMapping(h)%p => material_homogenizationMemberAt - deallocate(temperature (h)%p) allocate (temperature (h)%p(Nmaterialpoints), source=thermal_initialT(h)) - deallocate(temperatureRate(h)%p) allocate (temperatureRate(h)%p(Nmaterialpoints), source=0.0_pReal) end associate @@ -205,7 +197,7 @@ subroutine thermal_conduction_putTemperatureAndItsRate(T,Tdot,ip,el) offset homog = material_homogenizationAt(el) - offset = thermalMapping(homog)%p(ip,el) + offset = material_homogenizationMemberAt(ip,el) temperature (homog)%p(offset) = T temperatureRate(homog)%p(offset) = Tdot diff --git a/src/thermal_isothermal.f90 b/src/thermal_isothermal.f90 index 39c8efe91..2a41ada49 100644 --- a/src/thermal_isothermal.f90 +++ b/src/thermal_isothermal.f90 @@ -3,6 +3,7 @@ !> @brief material subroutine for isothermal temperature field !-------------------------------------------------------------------------------------------------- module thermal_isothermal + use prec use config use material @@ -24,15 +25,9 @@ subroutine thermal_isothermal_init if (thermal_type(h) /= THERMAL_isothermal_ID) cycle Nmaterialpoints = count(material_homogenizationAt == h) - thermalState(h)%sizeState = 0 - allocate(thermalState(h)%state0 (0,Nmaterialpoints)) - allocate(thermalState(h)%subState0(0,Nmaterialpoints)) - allocate(thermalState(h)%state (0,Nmaterialpoints)) - deallocate(temperature (h)%p) - allocate (temperature (h)%p(1), source=thermal_initialT(h)) - deallocate(temperatureRate(h)%p) - allocate (temperatureRate(h)%p(1)) + allocate(temperature (h)%p(Nmaterialpoints),source=thermal_initialT(h)) + allocate(temperatureRate(h)%p(Nmaterialpoints),source = 0.0_pReal) enddo